X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fconvert.cs;h=c1e9980f2931e3930c3e6599ac6f30e20cc45093;hb=d6513f517afde9ca1d13ca2c6dd539b539a9f0cf;hp=99459ab6c420c4fee599e930ac4d863d5184d210;hpb=5e03f444b9b775136b0af5133d61d4ff921ab39b;p=mono.git diff --git a/mcs/mcs/convert.cs b/mcs/mcs/convert.cs index 99459ab6c42..c1e9980f293 100644 --- a/mcs/mcs/convert.cs +++ b/mcs/mcs/convert.cs @@ -6,38 +6,42 @@ // Ravi Pratap (ravi@ximian.com) // Marek Safar (marek.safar@gmail.com) // -// (C) 2001, 2002, 2003 Ximian, Inc. +// Copyright 2001, 2002, 2003 Ximian, Inc. +// Copyright 2003-2008 Novell, Inc. // +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Reflection.Emit; + 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 { -#if GMCS_SOURCE - static bool TypeParameter_to_Null (Type target_type) + static class Convert { + + static EmptyExpression MyEmptyExpr; + static DoubleHash explicit_conv; + static DoubleHash implicit_conv; + + static Convert () { - GenericConstraints gc = TypeManager.GetTypeParameterConstraints (target_type); - if (gc == null) - return false; - - if (gc.HasReferenceTypeConstraint) - return true; - if (gc.HasClassConstraint && !TypeManager.IsValueType (gc.ClassConstraint)) - return true; - - return false; + Reset (); } - + + public static void Reset () + { + MyEmptyExpr = null; + explicit_conv = new DoubleHash (100); + implicit_conv = new DoubleHash (100); + } + static Type TypeParam_EffectiveBaseType (GenericConstraints gc) { - ArrayList list = new ArrayList (); + var list = new List (); list.Add (gc.EffectiveBaseClass); foreach (Type t in gc.InterfaceConstraints) { if (!TypeManager.IsGenericParameter (t)) @@ -49,75 +53,69 @@ namespace Mono.CSharp { } return FindMostEncompassedType (list); } -#endif - // - // From a one-dimensional array-type S[] to System.Collections.IList and base - // interfaces of this interface. // // From a one-dimensional array-type S[] to System.Collections.IList and base // interfaces of this interface, provided there is an implicit reference conversion // from S to T. // - static bool Array_To_IList (Type array, Type list) + static bool Array_To_IList (Type array, Type list, bool isExplicit) { -#if GMCS_SOURCE - if (!array.IsArray || (array.GetArrayRank () != 1) || !list.IsGenericType) + if ((array.GetArrayRank () != 1) || !TypeManager.IsGenericType (list)) return false; - Type gt = list.GetGenericTypeDefinition (); + Type gt = TypeManager.DropGenericTypeArguments (list); if ((gt != TypeManager.generic_ilist_type) && (gt != TypeManager.generic_icollection_type) && (gt != TypeManager.generic_ienumerable_type)) return false; Type element_type = TypeManager.GetElementType (array); - Type arg_type = TypeManager.GetTypeArguments (list) [0]; + Type arg_type = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (list) [0]); if (element_type == arg_type) return true; + if (isExplicit) + return ExplicitReferenceConversionExists (element_type, arg_type); + + Type t = TypeManager.GetElementType (array); if (MyEmptyExpr == null) - MyEmptyExpr = new EmptyExpression (); - MyEmptyExpr.SetType (TypeManager.GetElementType (array)); + MyEmptyExpr = new EmptyExpression (t); + else + MyEmptyExpr.SetType (t); - return ImplicitReferenceConversionCore (MyEmptyExpr, arg_type); -#else - return false; -#endif + return ImplicitReferenceConversionExists (MyEmptyExpr, arg_type); } static bool IList_To_Array(Type list, Type array) { -# if GMCS_SOURCE - if (!list.IsGenericType || !array.IsArray || array.GetArrayRank() != 1) + if (!TypeManager.IsGenericType (list) || !array.IsArray || array.GetArrayRank() != 1) return false; - Type gt = list.GetGenericTypeDefinition(); + Type gt = TypeManager.DropGenericTypeArguments (list); if (gt != TypeManager.generic_ilist_type && gt != TypeManager.generic_icollection_type && gt != TypeManager.generic_ienumerable_type) return false; - Type arg_type = TypeManager.GetTypeArguments(list)[0]; + Type arg_type = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments(list)[0]); Type element_type = TypeManager.GetElementType(array); if (element_type == arg_type) return true; if (MyEmptyExpr == null) - MyEmptyExpr = new EmptyExpression(); - MyEmptyExpr.SetType(element_type); + MyEmptyExpr = new EmptyExpression(element_type); + else + MyEmptyExpr.SetType(element_type); + return ImplicitReferenceConversionExists(MyEmptyExpr, arg_type) || ExplicitReferenceConversionExists(element_type, arg_type); -#else - return false; -#endif } static Expression ImplicitTypeParameterConversion (Expression expr, Type target_type) { -#if GMCS_SOURCE Type expr_type = expr.Type; GenericConstraints gc = TypeManager.GetTypeParameterConstraints (expr_type); @@ -155,14 +153,13 @@ namespace Mono.CSharp { if (TypeManager.ImplementsInterface (t, target_type)) return new ClassCast (expr, target_type); } -#endif + return null; } static bool ImplicitTypeParameterBoxingConversion (Type expr_type, Type target_type, out bool use_class_cast) { -#if GMCS_SOURCE GenericConstraints gc = TypeManager.GetTypeParameterConstraints (expr_type); if (gc == null) { @@ -201,62 +198,34 @@ namespace Mono.CSharp { if (TypeManager.ImplementsInterface (t, target_type)) return true; } -#endif use_class_cast = false; return false; } - static bool ExplicitTypeParameterConversionExists (Type source_type, Type target_type) + static Expression ExplicitTypeParameterConversion (Expression source, Type source_type, Type target_type) { -#if GMCS_SOURCE - if (target_type.IsInterface) - return true; - if (TypeManager.IsGenericParameter (target_type)) { GenericConstraints gc = TypeManager.GetTypeParameterConstraints (target_type); if (gc == null) - return false; + return null; foreach (Type iface in gc.InterfaceConstraints) { if (!TypeManager.IsGenericParameter (iface)) continue; if (TypeManager.IsSubclassOf (source_type, iface)) - return true; + return source == null ? EmptyExpression.Null : new ClassCast (source, target_type, true); } } -#endif - return false; - } - - static Expression ExplicitTypeParameterConversion (Expression source, Type target_type) - { -#if GMCS_SOURCE - Type source_type = source.Type; if (target_type.IsInterface) - return new ClassCast (source, target_type); + return source == null ? EmptyExpression.Null : new ClassCast (source, target_type, true); - if (TypeManager.IsGenericParameter (target_type)) { - GenericConstraints gc = TypeManager.GetTypeParameterConstraints (target_type); - if (gc == null) - return null; - - foreach (Type iface in gc.InterfaceConstraints) { - if (!TypeManager.IsGenericParameter (iface)) - continue; - - if (TypeManager.IsSubclassOf (source_type, iface)) - return new ClassCast (source, target_type); - } - } -#endif return null; } - static EmptyExpression MyEmptyExpr; - static public Expression ImplicitReferenceConversion (Expression expr, Type target_type) + static Expression ImplicitReferenceConversion (Expression expr, Type target_type, bool explicit_cast) { Type expr_type = expr.Type; @@ -277,11 +246,18 @@ namespace Mono.CSharp { // NullLiteral nl = expr as NullLiteral; if (nl != null) { - return nl.ConvertImplicitly(target_type); + return nl.ConvertImplicitly (null, target_type); } - if (ImplicitReferenceConversionCore (expr, target_type)) + if (ImplicitReferenceConversionExists (expr, target_type)) { + // + // Avoid wrapping implicitly convertible reference type + // + if (!explicit_cast) + return expr; + return EmptyCast.Create (expr, target_type); + } bool use_class_cast; if (ImplicitBoxingConversionExists (expr, target_type, out use_class_cast)) { @@ -294,15 +270,28 @@ namespace Mono.CSharp { return null; } - static public bool ImplicitReferenceConversionCore (Expression expr, Type target_type) + // + // 6.1.6 Implicit reference conversions + // + public static bool ImplicitReferenceConversionExists (Expression expr, Type target_type) { + if (TypeManager.IsStruct (target_type)) + return false; + Type expr_type = expr.Type; + // from the null type to any reference-type. + if (expr_type == TypeManager.null_type) + return target_type != InternalType.AnonymousMethod; + + if (TypeManager.IsGenericParameter (expr_type)) + return ImplicitTypeParameterConversion (expr, target_type) != 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) { + if (target_type == TypeManager.object_type || TypeManager.IsDynamicType (target_type)) { // // A pointer type cannot be converted to object // @@ -311,8 +300,10 @@ namespace Mono.CSharp { if (TypeManager.IsValueType (expr_type)) return false; + if (expr_type.IsClass || expr_type.IsInterface || expr_type == TypeManager.enum_type){ - return expr_type != TypeManager.anonymous_method_type; + // No mcs internal types are convertible + return expr_type.Module != typeof (Convert).Module; } return false; @@ -343,50 +334,60 @@ namespace Mono.CSharp { } } - // from any interface type S to interface-type T. - if (expr_type.IsInterface && target_type.IsInterface) { - return TypeManager.ImplementsInterface (expr_type, target_type); - } - - // 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 ()) { + if (expr_type.IsArray) { + // from an array-type S to an array-type of type T + if (target_type.IsArray && expr_type.GetArrayRank () == target_type.GetArrayRank ()) { + // + // Both SE and TE are reference-types + // Type expr_element_type = TypeManager.GetElementType (expr_type); + if (!TypeManager.IsReferenceType (expr_element_type)) + return false; - if (MyEmptyExpr == null) - MyEmptyExpr = new EmptyExpression (); - - MyEmptyExpr.SetType (expr_element_type); Type target_element_type = TypeManager.GetElementType (target_type); + if (!TypeManager.IsReferenceType (target_element_type)) + return false; - if (!expr_element_type.IsValueType && !target_element_type.IsValueType) - return ImplicitStandardConversionExists ( - MyEmptyExpr, target_element_type); + if (MyEmptyExpr == null) + MyEmptyExpr = new EmptyExpression (expr_element_type); + else + MyEmptyExpr.SetType (expr_element_type); + + return ImplicitStandardConversionExists (MyEmptyExpr, target_element_type); } + + // from an array-type to System.Array + if (target_type == TypeManager.array_type) + return true; + + // from an array-type of type T to IList + if (Array_To_IList (expr_type, target_type, false)) + return true; + + return false; } - // from an array-type to System.Array - if (expr_type.IsArray && target_type == TypeManager.array_type) + if (TypeManager.IsVariantOf (expr_type, target_type)) return true; - // from an array-type of type T to IList - if (expr_type.IsArray && Array_To_IList (expr_type, target_type)) - return true; + // from any interface type S to interface-type T. + if (expr_type.IsInterface && target_type.IsInterface) { + return TypeManager.ImplementsInterface (expr_type, target_type); + } // from any delegate type to System.Delegate if (target_type == TypeManager.delegate_type && (expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type))) return true; - // from a generic type definition to a generic instance. if (TypeManager.IsEqual (expr_type, target_type)) return true; return false; } - static public bool ImplicitBoxingConversionExists (Expression expr, Type target_type, + public static bool ImplicitBoxingConversionExists (Expression expr, Type target_type, out bool use_class_cast) { Type expr_type = expr.Type; @@ -395,7 +396,7 @@ namespace Mono.CSharp { // // From any value-type to the type object. // - if (target_type == TypeManager.object_type) { + if (target_type == TypeManager.object_type || TypeManager.IsDynamicType (target_type)) { // // A pointer type cannot be converted to object // @@ -415,17 +416,20 @@ namespace Mono.CSharp { // // From any enum-type to the type System.Enum. // - if (expr_type.IsEnum) + if (TypeManager.IsEnumType (expr_type)) return true; // // From any nullable-type with an underlying enum-type to the type System.Enum // if (TypeManager.IsNullableType (expr_type)) - return TypeManager.GetTypeArguments (expr_type) [0].IsEnum; + return TypeManager.IsEnumType (TypeManager.GetTypeArguments (expr_type) [0]); } - + if (TypeManager.IsSubclassOf (expr_type, target_type)) { - if (TypeManager.IsGenericParameter (expr_type)) + // + // Don't box same type arguments + // + if (TypeManager.IsGenericParameter (expr_type) && expr_type != target_type) return true; return false; @@ -450,31 +454,54 @@ namespace Mono.CSharp { return false; } - // - // Tests whether an implicit reference conversion exists between expr_type - // and target_type - // - public static bool ImplicitReferenceConversionExists (Expression expr, Type target_type) + public static Expression ImplicitNulableConversion (ResolveContext ec, Expression expr, Type target_type) { - if (target_type.IsValueType) - return false; - Type expr_type = expr.Type; - // from the null type to any reference-type. - if (expr_type == TypeManager.null_type){ - return true; + // + // From null to any nullable type + // + if (expr_type == TypeManager.null_type) + return ec == null ? EmptyExpression.Null : Nullable.LiftedNull.Create (target_type, expr.Location); + + // S -> T? + Type t_el = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (target_type)[0]); + + // S? -> T? + if (TypeManager.IsNullableType (expr_type)) + expr_type = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (expr_type)[0]); + + // + // Predefined implicit identity or implicit numeric conversion + // has to exist between underlying type S and underlying type T + // + + // Handles probing + if (ec == null) { + if (expr_type == t_el) + return EmptyExpression.Null; + + return ImplicitNumericConversion (null, expr_type, t_el); } - if (TypeManager.IsGenericParameter (expr_type)) - return ImplicitTypeParameterConversion (expr, target_type) != null; + Expression unwrap; + if (expr_type != expr.Type) + unwrap = Nullable.Unwrap.Create (expr); + else + unwrap = expr; - bool use_class_cast; - if (ImplicitReferenceConversionCore (expr, target_type) || - ImplicitBoxingConversionExists (expr, target_type, out use_class_cast)) - return true; + Expression conv = expr_type == t_el ? unwrap : ImplicitNumericConversion (unwrap, expr_type, t_el); + if (conv == null) + return null; - return false; + if (expr_type != expr.Type) + return new Nullable.Lifted (conv, unwrap, target_type).Resolve (ec); + + // Do constant optimization for S -> T? + if (unwrap is Constant) + conv = ((Constant) unwrap).ConvertImplicitly (ec, t_el); + + return Nullable.Wrap.Create (conv, target_type); } /// @@ -483,157 +510,150 @@ namespace Mono.CSharp { /// expr is the expression to convert, returns a new expression of type /// target_type or null if an implicit conversion is not possible. /// - static public Expression ImplicitNumericConversion (Expression expr, - Type target_type) + public static Expression ImplicitNumericConversion (Expression expr, Type target_type) { - Type expr_type = expr.Type; - Type real_target_type = target_type; + return ImplicitNumericConversion (expr, expr.Type, target_type); + } + static Expression ImplicitNumericConversion (Expression expr, Type expr_type, 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); + if (target_type == TypeManager.int32_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I4); + if (target_type == TypeManager.int64_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8); + if (target_type == TypeManager.double_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8); + if (target_type == TypeManager.float_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4); + if (target_type == TypeManager.short_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I2); + if (target_type == TypeManager.decimal_type) + return expr == null ? EmptyExpression.Null : 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 EmptyCast.Create (expr, target_type); + if (target_type == TypeManager.int32_type || target_type == TypeManager.uint32_type || + target_type == TypeManager.short_type || target_type == TypeManager.ushort_type) + return expr == null ? EmptyExpression.Null : EmptyCast.Create (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); + if (target_type == TypeManager.uint64_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8); + if (target_type == TypeManager.int64_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8); + if (target_type == TypeManager.float_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4); + if (target_type == TypeManager.double_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8); + if (target_type == TypeManager.decimal_type) + return expr == null ? EmptyExpression.Null : 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 EmptyCast.Create (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); + if (target_type == TypeManager.int32_type) + return expr == null ? EmptyExpression.Null : EmptyCast.Create (expr, target_type); + if (target_type == TypeManager.int64_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8); + if (target_type == TypeManager.double_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8); + if (target_type == TypeManager.float_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4); + if (target_type == TypeManager.decimal_type) + return expr == null ? EmptyExpression.Null : 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 EmptyCast.Create (expr, target_type); - - if (real_target_type == TypeManager.uint64_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U8); - 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.decimal_type) - return new CastToDecimal (expr); + if (target_type == TypeManager.int32_type || target_type == TypeManager.uint32_type) + return expr == null ? EmptyExpression.Null : EmptyCast.Create (expr, target_type); + + if (target_type == TypeManager.uint64_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8); + if (target_type == TypeManager.int64_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8); + if (target_type == TypeManager.double_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8); + if (target_type == TypeManager.float_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4); + if (target_type == TypeManager.decimal_type) + return expr == null ? EmptyExpression.Null : new CastToDecimal (expr); } else if (expr_type == TypeManager.int32_type){ // // From int to long, float, double, decimal // - 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); + if (target_type == TypeManager.int64_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8); + if (target_type == TypeManager.double_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8); + if (target_type == TypeManager.float_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4); + if (target_type == TypeManager.decimal_type) + return expr == null ? EmptyExpression.Null : new CastToDecimal (expr); } else if (expr_type == TypeManager.uint32_type){ // // From uint to long, ulong, float, double, decimal // - if (real_target_type == TypeManager.int64_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U8); - if (real_target_type == TypeManager.uint64_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U8); - if (real_target_type == TypeManager.double_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un, - OpCodes.Conv_R8); - if (real_target_type == TypeManager.float_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un, - OpCodes.Conv_R4); - if (real_target_type == TypeManager.decimal_type) - return new CastToDecimal (expr); + if (target_type == TypeManager.int64_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8); + if (target_type == TypeManager.uint64_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8); + if (target_type == TypeManager.double_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un), target_type, OpCodes.Conv_R8); + if (target_type == TypeManager.float_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un), target_type, OpCodes.Conv_R4); + if (target_type == TypeManager.decimal_type) + return expr == null ? EmptyExpression.Null : new CastToDecimal (expr); } else if (expr_type == TypeManager.int64_type){ // // From long/ulong to float, double // - 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); + if (target_type == TypeManager.double_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8); + if (target_type == TypeManager.float_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4); + if (target_type == TypeManager.decimal_type) + return expr == null ? EmptyExpression.Null : new CastToDecimal (expr); } else if (expr_type == TypeManager.uint64_type){ // // From ulong to float, double // - if (real_target_type == TypeManager.double_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un, - OpCodes.Conv_R8); - if (real_target_type == TypeManager.float_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un, - OpCodes.Conv_R4); - if (real_target_type == TypeManager.decimal_type) - return new CastToDecimal (expr); + if (target_type == TypeManager.double_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un), target_type, OpCodes.Conv_R8); + if (target_type == TypeManager.float_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un), target_type, OpCodes.Conv_R4); + if (target_type == TypeManager.decimal_type) + return expr == null ? EmptyExpression.Null : new CastToDecimal (expr); } else if (expr_type == TypeManager.char_type){ // // From char to ushort, int, uint, long, ulong, float, double, decimal // - if ((real_target_type == TypeManager.ushort_type) || - (real_target_type == TypeManager.int32_type) || - (real_target_type == TypeManager.uint32_type)) - return EmptyCast.Create (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); + if ((target_type == TypeManager.ushort_type) || + (target_type == TypeManager.int32_type) || + (target_type == TypeManager.uint32_type)) + return expr == null ? EmptyExpression.Null : EmptyCast.Create (expr, target_type); + if (target_type == TypeManager.uint64_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8); + if (target_type == TypeManager.int64_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8); + if (target_type == TypeManager.float_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4); + if (target_type == TypeManager.double_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8); + if (target_type == TypeManager.decimal_type) + return expr == null ? EmptyExpression.Null : new CastToDecimal (expr); } else if (expr_type == TypeManager.float_type){ // // float to double // - if (real_target_type == TypeManager.double_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_R8); + if (target_type == TypeManager.double_type) + return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8); } return null; @@ -643,26 +663,31 @@ namespace Mono.CSharp { /// Same as ImplicitStandardConversionExists except that it also looks at /// implicit user defined conversions - needed for overload resolution /// - public static bool ImplicitConversionExists (EmitContext ec, Expression expr, Type target_type) + public static bool ImplicitConversionExists (ResolveContext ec, Expression expr, Type target_type) { -#if GMCS_SOURCE - if (expr is NullLiteral) { - if (TypeManager.IsGenericParameter (target_type)) - return TypeParameter_to_Null (target_type); - - if (TypeManager.IsNullableType (target_type)) - return true; - } -#endif if (ImplicitStandardConversionExists (expr, target_type)) return true; - return ImplicitUserConversion (ec, expr, target_type, Location.Null) != null; - } + if (expr.Type == InternalType.AnonymousMethod) { + if (!TypeManager.IsDelegateType (target_type) && + TypeManager.DropGenericTypeArguments (target_type) != TypeManager.expression_type) + return false; - public static bool ImplicitUserConversionExists (EmitContext ec, Type source, Type target) - { - return ImplicitUserConversion (ec, new EmptyExpression (source), target, Location.Null) != null; + AnonymousMethodExpression ame = (AnonymousMethodExpression) expr; + return ame.ImplicitStandardConversionExists (ec, target_type); + } + + if (expr.eclass == ExprClass.MethodGroup) { + if (TypeManager.IsDelegateType (target_type) && RootContext.Version != LanguageVersion.ISO_1) { + MethodGroupExpr mg = expr as MethodGroupExpr; + if (mg != null) + return DelegateCreation.ImplicitStandardConversionExists (ec, mg, target_type); + } + + return false; + } + + return ImplicitUserConversion (ec, expr, target_type, Location.Null) != null; } /// @@ -674,148 +699,34 @@ namespace Mono.CSharp { public static bool ImplicitStandardConversionExists (Expression expr, Type target_type) { Type expr_type = expr.Type; -#if GMCS_SOURCE - if (TypeManager.IsNullableType (target_type)) { - // if implicit standard conversion S -> T exists, S -> T? and S? -> T? also exists - target_type = TypeManager.GetTypeArguments (target_type) [0]; - // S? -> T? - if (TypeManager.IsNullableType (expr_type)) { - EmptyExpression new_expr = EmptyExpression.Grab (); - new_expr.SetType (TypeManager.GetTypeArguments (expr_type) [0]); - bool retval = ImplicitStandardConversionExists (new_expr, target_type); - EmptyExpression.Release (new_expr); - return retval; - } + if (expr_type == TypeManager.null_type) { + NullLiteral nl = expr as NullLiteral; + if (nl != null) + return nl.ConvertImplicitly (null, target_type) != null; } -#endif + if (expr_type == TypeManager.void_type) return false; - //Console.WriteLine ("Expr is {0}", expr); - //Console.WriteLine ("{0} -> {1} ?", expr_type, target_type); if (TypeManager.IsEqual (expr_type, target_type)) return true; - - // First numeric conversions - - if (expr_type == TypeManager.sbyte_type){ - // - // From sbyte to short, int, long, float, double, decimal - // - if ((target_type == TypeManager.int32_type) || - (target_type == TypeManager.int64_type) || - (target_type == TypeManager.double_type) || - (target_type == TypeManager.float_type) || - (target_type == TypeManager.short_type) || - (target_type == TypeManager.decimal_type)) - return true; - - } else if (expr_type == TypeManager.byte_type){ - // - // From byte to short, ushort, int, uint, long, ulong, float, double, decimal - // - if ((target_type == TypeManager.short_type) || - (target_type == TypeManager.ushort_type) || - (target_type == TypeManager.int32_type) || - (target_type == TypeManager.uint32_type) || - (target_type == TypeManager.uint64_type) || - (target_type == TypeManager.int64_type) || - (target_type == TypeManager.float_type) || - (target_type == TypeManager.double_type) || - (target_type == TypeManager.decimal_type)) - return true; - - } else if (expr_type == TypeManager.short_type){ - // - // From short to int, long, double, float, decimal - // - if ((target_type == TypeManager.int32_type) || - (target_type == TypeManager.int64_type) || - (target_type == TypeManager.double_type) || - (target_type == TypeManager.float_type) || - (target_type == TypeManager.decimal_type)) - return true; - - } else if (expr_type == TypeManager.ushort_type){ - // - // From ushort to int, uint, long, ulong, double, float, decimal - // - if ((target_type == TypeManager.uint32_type) || - (target_type == TypeManager.uint64_type) || - (target_type == TypeManager.int32_type) || - (target_type == TypeManager.int64_type) || - (target_type == TypeManager.double_type) || - (target_type == TypeManager.float_type) || - (target_type == TypeManager.decimal_type)) - return true; - - } else if (expr_type == TypeManager.int32_type){ - // - // From int to long, double, float, decimal - // - if ((target_type == TypeManager.int64_type) || - (target_type == TypeManager.double_type) || - (target_type == TypeManager.float_type) || - (target_type == TypeManager.decimal_type)) - return true; - - } else if (expr_type == TypeManager.uint32_type){ - // - // From uint to long, ulong, double, float, decimal - // - if ((target_type == TypeManager.int64_type) || - (target_type == TypeManager.uint64_type) || - (target_type == TypeManager.double_type) || - (target_type == TypeManager.float_type) || - (target_type == TypeManager.decimal_type)) - return true; - - } else if ((expr_type == TypeManager.uint64_type) || - (expr_type == TypeManager.int64_type)) { - // - // From long/ulong to double, float, decimal - // - if ((target_type == TypeManager.double_type) || - (target_type == TypeManager.float_type) || - (target_type == TypeManager.decimal_type)) - return true; - - } else if (expr_type == TypeManager.char_type){ - // - // From char to ushort, int, uint, ulong, long, float, double, decimal - // - if ((target_type == TypeManager.ushort_type) || - (target_type == TypeManager.int32_type) || - (target_type == TypeManager.uint32_type) || - (target_type == TypeManager.uint64_type) || - (target_type == TypeManager.int64_type) || - (target_type == TypeManager.float_type) || - (target_type == TypeManager.double_type) || - (target_type == TypeManager.decimal_type)) - return true; - - } else if (expr_type == TypeManager.float_type){ - // - // float to double - // - if (target_type == TypeManager.double_type) - return true; + if (TypeManager.IsNullableType (target_type)) { + return ImplicitNulableConversion (null, expr, target_type) != null; } - if (expr.eclass == ExprClass.MethodGroup){ - if (TypeManager.IsDelegateType (target_type) && RootContext.Version != LanguageVersion.ISO_1){ - MethodGroupExpr mg = expr as MethodGroupExpr; - if (mg != null){ - return DelegateCreation.ImplicitStandardConversionExists (mg, target_type) != null; - } - } - } + // First numeric conversions + if (ImplicitNumericConversion (null, expr_type, target_type) != null) + return true; if (ImplicitReferenceConversionExists (expr, target_type)) return true; + bool use_class_cast; + if (ImplicitBoxingConversionExists (expr, target_type, out use_class_cast)) + return true; + // // Implicit Constant Expression Conversions // @@ -847,7 +758,7 @@ namespace Mono.CSharp { return true; } - if (value == 0 && expr is IntLiteral && TypeManager.IsEnumType (target_type)) + if (value == 0 && TypeManager.IsEnumType (target_type)) return true; } @@ -866,20 +777,15 @@ namespace Mono.CSharp { // If `expr_type' implements `target_type' (which is an iface) // see TryImplicitIntConversion // - if (target_type.IsInterface && target_type.IsAssignableFrom (expr_type)) + if (target_type.IsInterface && TypeManager.ImplementsInterface (expr_type, target_type)) return true; if (target_type == TypeManager.void_ptr_type && expr_type.IsPointer) return true; - if (expr_type == TypeManager.anonymous_method_type){ - if (!TypeManager.IsDelegateType (target_type) && - TypeManager.DropGenericTypeArguments (target_type) != TypeManager.expression_type) - return false; - - AnonymousMethodExpression ame = (AnonymousMethodExpression) expr; - return ame.ImplicitStandardConversionExists (target_type); - } + // Conversion from __arglist to System.ArgIterator + if (expr_type == InternalType.Arglist) + return target_type == TypeManager.arg_iterator_type; return false; } @@ -888,7 +794,7 @@ namespace Mono.CSharp { /// Finds "most encompassed type" according to the spec (13.4.2) /// amongst the methods in the MethodGroupExpr /// - static Type FindMostEncompassedType (ArrayList types) + static Type FindMostEncompassedType (IList types) { Type best = null; @@ -930,7 +836,7 @@ namespace Mono.CSharp { /// Finds "most encompassing type" according to the spec (13.4.2) /// amongst the types in the given set /// - static Type FindMostEncompassingType (ArrayList types) + static Type FindMostEncompassingType (IList types) { Type best = null; @@ -938,7 +844,7 @@ namespace Mono.CSharp { return null; if (types.Count == 1) - return (Type) types [0]; + return types [0]; EmptyExpression expr = EmptyExpression.Grab (); @@ -973,18 +879,18 @@ namespace Mono.CSharp { /// by making use of FindMostEncomp* methods. Applies the correct rules separately /// for explicit and implicit conversion operators. /// - static public Type FindMostSpecificSource (IList list, + static public Type FindMostSpecificSource (IList list, Expression source, bool apply_explicit_conv_rules) { - ArrayList src_types_set = new ArrayList (); + var src_types_set = new List (); // // If any operator converts from S then Sx = S // Type source_type = source.Type; foreach (MethodBase mb in list){ - ParameterData pd = TypeManager.GetParameterData (mb); - Type param_type = pd.ParameterType (0); + AParametersCollection pd = TypeManager.GetParameterData (mb); + Type param_type = pd.Types [0]; if (param_type == source_type) return param_type; @@ -996,7 +902,7 @@ namespace Mono.CSharp { // Explicit Conv rules // if (apply_explicit_conv_rules) { - ArrayList candidate_set = new ArrayList (); + var candidate_set = new List (); foreach (Type param_type in src_types_set){ if (ImplicitStandardConversionExists (source, param_type)) @@ -1019,10 +925,10 @@ namespace Mono.CSharp { /// /// Finds the most specific target Tx according to section 13.4.4 /// - static public Type FindMostSpecificTarget (IList list, + static public Type FindMostSpecificTarget (IList list, Type target, bool apply_explicit_conv_rules) { - ArrayList tgt_types_set = new ArrayList (); + var tgt_types_set = new List (); // // If any operator converts to T then Tx = T @@ -1039,7 +945,7 @@ namespace Mono.CSharp { // Explicit conv rules // if (apply_explicit_conv_rules) { - ArrayList candidate_set = new ArrayList (); + var candidate_set = new List (); EmptyExpression expr = EmptyExpression.Grab (); @@ -1068,22 +974,22 @@ namespace Mono.CSharp { /// /// User-defined Implicit conversions /// - static public Expression ImplicitUserConversion (EmitContext ec, Expression source, + static public Expression ImplicitUserConversion (ResolveContext ec, Expression source, Type target, Location loc) { - return UserDefinedConversion (ec, source, target, loc, false); + return UserDefinedConversion (ec, source, target, loc, false, true); } /// /// User-defined Explicit conversions /// - static public Expression ExplicitUserConversion (EmitContext ec, Expression source, + static Expression ExplicitUserConversion (ResolveContext ec, Expression source, Type target, Location loc) { - return UserDefinedConversion (ec, source, target, loc, true); + return UserDefinedConversion (ec, source, target, loc, true, true); } - static void AddConversionOperators (ArrayList list, + static void AddConversionOperators (List list, Expression source, Type target_type, bool look_for_explicit, MethodGroupExpr mg) @@ -1093,10 +999,24 @@ namespace Mono.CSharp { Type source_type = source.Type; EmptyExpression expr = EmptyExpression.Grab (); + + // + // LAMESPEC: Undocumented IntPtr/UIntPtr conversions + // IntPtr -> uint uses int + // UIntPtr -> long uses ulong + // + if (source_type == TypeManager.intptr_type) { + if (target_type == TypeManager.uint32_type) + target_type = TypeManager.int32_type; + } else if (source_type == TypeManager.uintptr_type) { + if (target_type == TypeManager.int64_type) + target_type = TypeManager.uint64_type; + } + foreach (MethodInfo m in mg.Methods) { - ParameterData pd = TypeManager.GetParameterData (m); + AParametersCollection pd = TypeManager.GetParameterData (m); Type return_type = TypeManager.TypeToCoreType (m.ReturnType); - Type arg_type = pd.ParameterType (0); + Type arg_type = pd.Types [0]; if (source_type != arg_type) { if (!ImplicitStandardConversionExists (source, arg_type)) { @@ -1119,6 +1039,10 @@ namespace Mono.CSharp { } } + // See LAMESPEC: Exclude IntPtr -> int conversion + if (source_type == TypeManager.uintptr_type && return_type == TypeManager.uint32_type) + continue; + list.Add (m); } @@ -1129,28 +1053,28 @@ namespace Mono.CSharp { /// Compute the user-defined conversion operator from source_type to target_type. /// `look_for_explicit' controls whether we should also include the list of explicit operators /// - static MethodInfo GetConversionOperator (Type container_type, Expression source, Type target_type, bool look_for_explicit) + static MethodInfo GetConversionOperator (CompilerContext ctx, Type container_type, Expression source, Type target_type, bool look_for_explicit) { - ArrayList ops = new ArrayList (4); + var ops = new List (4); Type source_type = source.Type; if (source_type != TypeManager.decimal_type) { AddConversionOperators (ops, source, target_type, look_for_explicit, - Expression.MethodLookup (container_type, source_type, "op_Implicit", Location.Null) as MethodGroupExpr); + Expression.MethodLookup (ctx, container_type, source_type, "op_Implicit", Location.Null) as MethodGroupExpr); if (look_for_explicit) { AddConversionOperators (ops, source, target_type, look_for_explicit, - Expression.MethodLookup ( + Expression.MethodLookup (ctx, container_type, source_type, "op_Explicit", Location.Null) as MethodGroupExpr); } } if (target_type != TypeManager.decimal_type) { AddConversionOperators (ops, source, target_type, look_for_explicit, - Expression.MethodLookup (container_type, target_type, "op_Implicit", Location.Null) as MethodGroupExpr); + Expression.MethodLookup (ctx, container_type, target_type, "op_Implicit", Location.Null) as MethodGroupExpr); if (look_for_explicit) { AddConversionOperators (ops, source, target_type, look_for_explicit, - Expression.MethodLookup ( + Expression.MethodLookup (ctx, container_type, target_type, "op_Explicit", Location.Null) as MethodGroupExpr); } } @@ -1171,7 +1095,7 @@ namespace Mono.CSharp { foreach (MethodInfo m in ops) { if (TypeManager.TypeToCoreType (m.ReturnType) != most_specific_target) continue; - if (TypeManager.GetParameterData (m).ParameterType (0) != most_specific_source) + if (TypeManager.GetParameterData (m).Types [0] != most_specific_source) continue; // Ambiguous: more than one conversion operator satisfies the signature. if (method != null) @@ -1182,59 +1106,109 @@ namespace Mono.CSharp { return method; } - static DoubleHash explicit_conv = new DoubleHash (100); - static DoubleHash implicit_conv = new DoubleHash (100); - /// /// User-defined conversions /// - static public Expression UserDefinedConversion (EmitContext ec, Expression source, + public static Expression UserDefinedConversion (ResolveContext ec, Expression source, Type target, Location loc, - bool look_for_explicit) + bool look_for_explicit, bool return_convert) { Type source_type = source.Type; MethodInfo method = null; + Expression expr = null; object o; - DoubleHash hash = look_for_explicit ? explicit_conv : implicit_conv; + DoubleHash hash; + if (look_for_explicit) { + hash = explicit_conv; + } else { + // Implicit user operators cannot convert to interfaces + if (target.IsInterface) + return null; + + hash = implicit_conv; + } if (!(source is Constant) && hash.Lookup (source_type, target, out o)) { method = (MethodInfo) o; } else { - method = GetConversionOperator (null, source, target, look_for_explicit); - if (!(source is Constant)) - hash.Insert (source_type, target, method); + if (TypeManager.IsDynamicType (source_type)) + return null; + + method = GetConversionOperator (ec.Compiler, null, source, target, look_for_explicit); } - if (method == null) - return null; + if (method != null) { + Type most_specific_source = TypeManager.GetParameterData (method).Types[0]; - Type most_specific_source = TypeManager.GetParameterData (method).ParameterType (0); + // + // This will do the conversion to the best match that we + // found. Now we need to perform an implict standard conversion + // if the best match was not the type that we were requested + // by target. + // + if (look_for_explicit) { + ReportPrinter temp = new SessionReportPrinter (); + ReportPrinter prev = ec.Report.SetPrinter (temp); - // - // This will do the conversion to the best match that we - // found. Now we need to perform an implict standard conversion - // if the best match was not the type that we were requested - // by target. - // - if (look_for_explicit) - source = ExplicitConversionStandard (ec, source, most_specific_source, loc); - else - source = ImplicitConversionStandard (ec, source, most_specific_source, loc); + expr = ExplicitConversionStandard (ec, source, most_specific_source, loc); - if (source == null) - return null; + ec.Report.SetPrinter (prev); + if (temp.ErrorsCount != 0) + expr = null; + } else { + if (ImplicitStandardConversionExists (source, most_specific_source)) + expr = ImplicitConversionStandard (ec, source, most_specific_source, loc); + else + expr = null; + } + } - Expression e; - e = new UserCast (method, source, loc); - if (e.Type != target){ - if (!look_for_explicit) - e = ImplicitConversionStandard (ec, e, target, loc); - else - e = ExplicitConversionStandard (ec, e, target, loc); + if (expr == null) { + bool nullable = false; + + if (TypeManager.IsNullableType (source_type)) { + source = Nullable.Unwrap.Create (source); + nullable = true; + } + + Type target_underlying; + if (TypeManager.IsNullableType (target)) { + target_underlying = TypeManager.GetTypeArguments (target)[0]; + nullable = true; + } else { + // No implicit conversion S? -> T for non-reference type T + if (!look_for_explicit && !TypeManager.IsReferenceType (target)) + nullable = false; + + target_underlying = target; + } + + if (nullable) { + expr = UserDefinedConversion (ec, source, target_underlying, loc, look_for_explicit, return_convert); + + // Do result expression lifting only when it's needed + if (expr != null && (!look_for_explicit || TypeManager.IsReferenceType (target))) + expr = new Nullable.Lifted (expr, source, target).Resolve (ec); + + return expr; + } + } else { + expr = new UserCast (method, expr, loc).Resolve (ec); + + if (return_convert && !TypeManager.IsEqual (expr.Type, target)) { + if (look_for_explicit) { + expr = ExplicitConversionStandard (ec, expr, target, loc); + } else { + expr = ImplicitConversionStandard (ec, expr, target, loc); + } + } } - return e; + if (!(source is Constant)) + hash.Insert (source_type, target, method); + + return expr; } /// @@ -1242,7 +1216,7 @@ namespace Mono.CSharp { /// `target_type'. It returns a new expression that can be used /// in a context that expects a `target_type'. /// - static public Expression ImplicitConversion (EmitContext ec, Expression expr, + static public Expression ImplicitConversion (ResolveContext ec, Expression expr, Type target_type, Location loc) { Expression e; @@ -1272,34 +1246,14 @@ namespace Mono.CSharp { /// This is different from `ImplicitConversion' in that the /// user defined implicit conversions are excluded. /// - static public Expression ImplicitConversionStandard (EmitContext ec, Expression expr, + static public Expression ImplicitConversionStandard (ResolveContext ec, Expression expr, Type target_type, Location loc) { - Type expr_type = expr.Type; - Expression e; - -#if GMCS_SOURCE - if (TypeManager.IsNullableType (target_type)) { - // - // From null to any nullable type - // - if (expr_type == TypeManager.null_type) - return Nullable.LiftedNull.Create (target_type, loc); - - Type target = TypeManager.GetTypeArguments (target_type) [0]; + return ImplicitConversionStandard (ec, expr, target_type, loc, false); + } - if (TypeManager.IsNullableType (expr.Type)) { - e = new Nullable.LiftedConversion ( - expr, target_type, false, false, loc).Resolve (ec); - if (e != null) - return e; - } else { - e = ImplicitConversion (ec, expr, target, loc); - if (e != null) - return Nullable.Wrap.Create (e, target_type); - } - } -#endif + static Expression ImplicitConversionStandard (ResolveContext ec, Expression expr, Type target_type, Location loc, bool explicit_cast) + { if (expr.eclass == ExprClass.MethodGroup){ if (!TypeManager.IsDelegateType (target_type)){ return null; @@ -1316,23 +1270,29 @@ namespace Mono.CSharp { } } - if (expr_type.Equals (target_type) && expr_type != TypeManager.null_type) + Type expr_type = expr.Type; + Expression e; + + if (expr_type.Equals (target_type)) { + if (expr_type != TypeManager.null_type && expr_type != InternalType.AnonymousMethod) + return expr; + return null; + } + + if (TypeManager.IsVariantOf (expr_type, target_type)) { return expr; + } + + if (TypeManager.IsNullableType (target_type)) + return ImplicitNulableConversion (ec, expr, target_type); // // Attempt to do the implicit constant expression conversions // Constant c = expr as Constant; if (c != null) { - // - // If `target_type' is an interface and the type of `ic' implements the interface - // e.g. target_type is IComparable, IConvertible, IFormattable - // - if (c.Type == TypeManager.int32_type && target_type.IsInterface && target_type.IsAssignableFrom (c.Type)) - return new BoxedCast (c, target_type); - try { - c = c.ConvertImplicitly (target_type); + c = c.ConvertImplicitly (ec, target_type); } catch { Console.WriteLine ("Conversion error happened in line {0}", loc); throw; @@ -1341,22 +1301,28 @@ namespace Mono.CSharp { return c; } - e = ImplicitNumericConversion (expr, target_type); + e = ImplicitNumericConversion (expr, expr_type, target_type); if (e != null) return e; - e = ImplicitReferenceConversion (expr, target_type); + e = ImplicitReferenceConversion (expr, target_type, explicit_cast); if (e != null) return e; - if (TypeManager.IsEnumType (target_type) && expr is IntLiteral){ - IntLiteral i = (IntLiteral) expr; - - if (i.Value == 0) - return new EnumConstant ((Constant) expr, target_type); + if (expr is IntConstant && TypeManager.IsEnumType (target_type)){ + Constant i = (Constant) expr; + // + // LAMESPEC: Conversion from any 0 constant is allowed + // + // An implicit enumeration conversion permits the decimal-integer-literal 0 + // to be converted to any enum-type and to any nullable-type whose underlying + // type is an enum-type + // + if (i.IsDefaultValue) + return new EnumConstant (i, target_type).Resolve (ec); } - if (ec.InUnsafe) { + if (ec.IsUnsafe) { if (expr_type.IsPointer){ if (target_type == TypeManager.void_ptr_type) return EmptyCast.Create (expr, target_type); @@ -1374,16 +1340,19 @@ namespace Mono.CSharp { } if (expr_type == TypeManager.null_type && target_type.IsPointer) - return EmptyCast.Create (NullPointer.Null, target_type); + return EmptyCast.Create (new NullPointer (loc), target_type); } - if (expr_type == TypeManager.anonymous_method_type){ + if (expr_type == InternalType.AnonymousMethod){ AnonymousMethodExpression ame = (AnonymousMethodExpression) expr; Expression am = ame.Compatible (ec, target_type); if (am != null) - return am.DoResolve (ec); + return am.Resolve (ec); } + if (expr_type == InternalType.Arglist && target_type == TypeManager.arg_iterator_type) + return expr; + return null; } @@ -1392,13 +1361,19 @@ namespace Mono.CSharp { /// ImplicitConversion. If there is no implicit conversion, then /// an error is signaled /// - static public Expression ImplicitConversionRequired (EmitContext ec, Expression source, + static public Expression ImplicitConversionRequired (ResolveContext ec, Expression source, Type target_type, Location loc) { Expression e = ImplicitConversion (ec, source, target_type, loc); if (e != null) return e; + if (TypeManager.IsDynamicType (source.Type)) { + Arguments args = new Arguments (1); + args.Add (new Argument (source)); + return new DynamicConversion (target_type, 0, args, loc).Resolve (ec); + } + source.Error_ValueCannotBeConverted (ec, loc, target_type, false); return null; } @@ -1679,164 +1654,61 @@ namespace Mono.CSharp { /// public static bool ExplicitReferenceConversionExists (Type source_type, Type target_type) { - bool target_is_type_param = TypeManager.IsGenericParameter (target_type); - bool target_is_value_type = target_type.IsValueType; - - if (source_type == target_type) - return true; - - // - // From generic parameter to any type - // - if (TypeManager.IsGenericParameter (source_type)) - return ExplicitTypeParameterConversionExists (source_type, target_type); - - // - // From object to a generic parameter - // - if (source_type == TypeManager.object_type && target_is_type_param) - return true; - - // - // From object to any reference type - // - if (source_type == TypeManager.object_type && !target_is_value_type) - return true; - - // - // From any class S to any class-type T, provided S is a base class of T - // - if (TypeManager.IsSubclassOf (target_type, source_type)) - return true; - - // - // From any interface type S to any interface T provided S is not derived from T - // - if (source_type.IsInterface && target_type.IsInterface){ - if (!TypeManager.IsSubclassOf (target_type, source_type)) - return true; - } - - // - // From any class type S to any interface T, provided S is not sealed - // and provided S does not implement T. - // - if (target_type.IsInterface && !source_type.IsSealed && - !TypeManager.ImplementsInterface (source_type, target_type)) - return true; - - // - // From any interface-type S to to any class type T, provided T is not - // sealed, or provided T implements S. - // - if (source_type.IsInterface && - (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type))) - return true; - - - if (source_type.IsInterface && IList_To_Array (source_type, target_type)) - return true; - - // From an array type S with an element type Se to an array type T with an - // element type Te provided all the following are true: - // * S and T differe only in element type, in other words, S and T - // have the same number of dimensions. - // * Both Se and Te are reference types - // * An explicit referenc conversions exist from Se to Te - // - if (source_type.IsArray && target_type.IsArray) { - if (source_type.GetArrayRank () == target_type.GetArrayRank ()) { - - Type source_element_type = TypeManager.GetElementType (source_type); - Type target_element_type = TypeManager.GetElementType (target_type); - - if (TypeManager.IsGenericParameter (source_element_type) || - (!source_element_type.IsValueType && !target_element_type.IsValueType)) - if (ExplicitReferenceConversionExists (source_element_type, - target_element_type)) - return true; - } - } - - - // From System.Array to any array-type - if (source_type == TypeManager.array_type && - target_type.IsArray){ - return true; - } + Expression e = ExplicitReferenceConversion (null, source_type, target_type); + if (e == null) + return false; - // - // From System delegate to any delegate-type - // - if (source_type == TypeManager.delegate_type && - TypeManager.IsDelegateType (target_type)) + if (e == EmptyExpression.Null) return true; - return false; + throw new InternalErrorException ("Invalid probing conversion result"); } /// /// Implements Explicit Reference conversions /// - static Expression ExplicitReferenceConversion (Expression source, Type target_type) + static Expression ExplicitReferenceConversion (Expression source, Type source_type, Type target_type) { - Type source_type = source.Type; - bool target_is_type_param = TypeManager.IsGenericParameter (target_type); - bool target_is_value_type = target_type.IsValueType; + bool target_is_value_type = TypeManager.IsStruct (target_type); // // From object to a generic parameter // - if (source_type == TypeManager.object_type && target_is_type_param) - return new UnboxCast (source, target_type); + if (source_type == TypeManager.object_type && TypeManager.IsGenericParameter (target_type)) + return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type); // // Explicit type parameter conversion. // - if (TypeManager.IsGenericParameter (source_type)) - return ExplicitTypeParameterConversion (source, target_type); + return ExplicitTypeParameterConversion (source, source_type, target_type); // - // From object to any reference type + // From object to any reference type or value type (unboxing) // - if (source_type == TypeManager.object_type && !target_is_value_type) - return new ClassCast (source, target_type); + if (source_type == TypeManager.object_type) + return source == null ? EmptyExpression.Null : + target_is_value_type ? (Expression) new UnboxCast (source, target_type) : new ClassCast (source, target_type); // - // Unboxing conversion. + // Unboxing conversion from the types object and System.ValueType to any non-nullable-value-type // - if (((source_type == TypeManager.enum_type && - !(source is EmptyCast)) || - source_type == TypeManager.value_type) && target_is_value_type) - return new UnboxCast (source, target_type); + if (source_type == TypeManager.value_type && target_is_value_type) + return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type); // // From any class S to any class-type T, provided S is a base class of T // if (TypeManager.IsSubclassOf (target_type, source_type)) - return new ClassCast (source, target_type); - - // - // From any interface type S to any interface T provided S is not derived from T - // - if (source_type.IsInterface && target_type.IsInterface){ - if (TypeManager.ImplementsInterface (source_type, target_type)) - return null; - else - return new ClassCast (source, target_type); - } + return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); // // From any class type S to any interface T, provides S is not sealed // and provided S does not implement T. // - if (target_type.IsInterface && !source_type.IsSealed) { - if (TypeManager.ImplementsInterface (source_type, target_type)) - return null; - else - return new ClassCast (source, target_type); - + if (target_type.IsInterface && !source_type.IsSealed && + !TypeManager.ImplementsInterface (source_type, target_type)) { + return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); } // @@ -1846,9 +1718,13 @@ namespace Mono.CSharp { if (source_type.IsInterface) { if (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)) { if (target_type.IsClass) - return new ClassCast (source, target_type); - else - return new UnboxCast (source, target_type); + return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); + + // + // Unboxing conversion from any interface-type to any non-nullable-value-type that + // implements the interface-type + // + return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type); } // @@ -1856,44 +1732,59 @@ namespace Mono.CSharp { // array type S[], provided there is an implicit or explicit reference conversion from S to T. // if (IList_To_Array (source_type, target_type)) - return new ClassCast (source, target_type); + return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); return null; } - // From an array type S with an element type Se to an array type T with an - // element type Te provided all the following are true: - // * S and T differe only in element type, in other words, S and T - // have the same number of dimensions. - // * Both Se and Te are reference types - // * An explicit referenc conversions exist from Se to Te - // - if (source_type.IsArray && target_type.IsArray) { - if (source_type.GetArrayRank () == target_type.GetArrayRank ()) { + if (source_type.IsArray) { + if (target_type.IsArray) { + // + // From System.Array to any array-type + // + if (source_type == TypeManager.array_type) + return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); - Type source_element_type = TypeManager.GetElementType (source_type); - Type target_element_type = TypeManager.GetElementType (target_type); + // + // From an array type S with an element type Se to an array type T with an + // element type Te provided all the following are true: + // * S and T differe only in element type, in other words, S and T + // have the same number of dimensions. + // * Both Se and Te are reference types + // * An explicit reference conversions exist from Se to Te + // + if (source_type.GetArrayRank () == target_type.GetArrayRank ()) { - if (!source_element_type.IsValueType && !target_element_type.IsValueType) - if (ExplicitReferenceConversionExists (source_element_type, - target_element_type)) - return new ClassCast (source, target_type); + source_type = TypeManager.GetElementType (source_type); + if (!TypeManager.IsReferenceType (source_type)) + return null; + + Type target_type_element = TypeManager.GetElementType (target_type); + if (!TypeManager.IsReferenceType (target_type_element)) + return null; + + if (ExplicitReferenceConversionExists (source_type, target_type_element)) + return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); + + return null; + } } - } + // + // From a single-dimensional array type S[] to System.Collections.Generic.IList and its base interfaces, + // provided that there is an explicit reference conversion from S to T + // + if (Array_To_IList (source_type, target_type, true)) + return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); - // From System.Array to any array-type - if (source_type == TypeManager.array_type && - target_type.IsArray) { - return new ClassCast (source, target_type); + return null; } // // From System delegate to any delegate-type // - if (source_type == TypeManager.delegate_type && - TypeManager.IsDelegateType (target_type)) - return new ClassCast (source, target_type); + if (source_type == TypeManager.delegate_type && TypeManager.IsDelegateType (target_type)) + return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); return null; } @@ -1902,22 +1793,16 @@ namespace Mono.CSharp { /// Performs an explicit conversion of the expression `expr' whose /// type is expr.Type to `target_type'. /// - static public Expression ExplicitConversionCore (EmitContext ec, Expression expr, + static public Expression ExplicitConversionCore (ResolveContext ec, Expression expr, Type target_type, Location loc) { Type expr_type = expr.Type; // Explicit conversion includes implicit conversion and it used for enum underlying types too - Expression ne = ImplicitConversionStandard (ec, expr, target_type, loc); + Expression ne = ImplicitConversionStandard (ec, expr, target_type, loc, true); if (ne != null) return ne; - // - // Unboxing conversions; only object types can be convertible to enum - // - if (expr_type == TypeManager.object_type && target_type.IsValueType) - return new UnboxCast (expr, target_type); - if (TypeManager.IsEnumType (expr_type)) { Expression underlying = EmptyCast.Create (expr, TypeManager.GetEnumUnderlyingType (expr_type)); expr = ExplicitConversionCore (ec, underlying, target_type, loc); @@ -1928,6 +1813,9 @@ namespace Mono.CSharp { } if (TypeManager.IsEnumType (target_type)){ + // + // Type System.Enum can be unboxed to any enum-type + // if (expr_type == TypeManager.enum_type) return new UnboxCast (expr, target_type); @@ -1938,11 +1826,11 @@ namespace Mono.CSharp { // // LAMESPEC: IntPtr and UIntPtr conversion to any Enum is allowed // - if (expr_type == TypeManager.intptr_type || expr_type == TypeManager.uintptr_type) { + if (expr_type == TypeManager.intptr_type || expr_type == TypeManager.uintptr_type) { ne = ExplicitUserConversion (ec, expr, TypeManager.GetEnumUnderlyingType (target_type), loc); if (ne != null) return ExplicitConversionCore (ec, ne, target_type, loc); - } + } return null; } @@ -1957,12 +1845,12 @@ namespace Mono.CSharp { // null literal explicitly // if (expr_type != TypeManager.null_type){ - ne = ExplicitReferenceConversion (expr, target_type); + ne = ExplicitReferenceConversion (expr, expr_type, target_type); if (ne != null) return ne; } - if (ec.InUnsafe){ + if (ec.IsUnsafe){ ne = ExplicitUnsafe (expr, target_type); if (ne != null) return ne; @@ -1981,35 +1869,38 @@ namespace Mono.CSharp { if (expr_type == TypeManager.sbyte_type || expr_type == TypeManager.short_type || - expr_type == TypeManager.int32_type || - expr_type == TypeManager.int64_type) + expr_type == TypeManager.int32_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_I); if (expr_type == TypeManager.ushort_type || expr_type == TypeManager.uint32_type || - expr_type == TypeManager.uint64_type || expr_type == TypeManager.byte_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_U); + + if (expr_type == TypeManager.int64_type) + return new ConvCast (expr, target_type, ConvCast.Mode.I8_I); + + if (expr_type == TypeManager.uint64_type) + return new ConvCast (expr, target_type, ConvCast.Mode.U8_I); } if (expr_type.IsPointer){ if (target_type == TypeManager.sbyte_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_I1); - else if (target_type == TypeManager.byte_type) + if (target_type == TypeManager.byte_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_U1); - else if (target_type == TypeManager.short_type) + if (target_type == TypeManager.short_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_I2); - else if (target_type == TypeManager.ushort_type) + if (target_type == TypeManager.ushort_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); - else if (target_type == TypeManager.int32_type) + if (target_type == TypeManager.int32_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_I4); - else if (target_type == TypeManager.uint32_type) + if (target_type == TypeManager.uint32_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_U4); - else if (target_type == TypeManager.uint64_type) + if (target_type == TypeManager.int64_type) + return new ConvCast (expr, target_type, ConvCast.Mode.I_I8); + if (target_type == TypeManager.uint64_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_U8); - else if (target_type == TypeManager.int64_type){ - return new OpcodeCast (expr, target_type, OpCodes.Conv_I8); - } } return null; } @@ -2017,12 +1908,12 @@ namespace Mono.CSharp { /// /// Same as ExplicitConversion, only it doesn't include user defined conversions /// - static public Expression ExplicitConversionStandard (EmitContext ec, Expression expr, + static public Expression ExplicitConversionStandard (ResolveContext ec, Expression expr, Type target_type, Location l) { - int errors = Report.Errors; + int errors = ec.Report.Errors; Expression ne = ImplicitConversionStandard (ec, expr, target_type, l); - if (Report.Errors > errors) + if (ec.Report.Errors > errors) return null; if (ne != null) @@ -2032,11 +1923,11 @@ namespace Mono.CSharp { if (ne != null) return ne; - ne = ExplicitReferenceConversion (expr, target_type); + ne = ExplicitReferenceConversion (expr, expr.Type, target_type); if (ne != null) return ne; - if (ec.InUnsafe && expr.Type == TypeManager.void_ptr_type && target_type.IsPointer) + if (ec.IsUnsafe && expr.Type == TypeManager.void_ptr_type && target_type.IsPointer) return EmptyCast.Create (expr, target_type); expr.Error_ValueCannotBeConverted (ec, l, target_type, true); @@ -2047,43 +1938,55 @@ namespace Mono.CSharp { /// Performs an explicit conversion of the expression `expr' whose /// type is expr.Type to `target_type'. /// - static public Expression ExplicitConversion (EmitContext ec, Expression expr, + static public Expression ExplicitConversion (ResolveContext ec, Expression expr, Type target_type, Location loc) { - Expression e; -#if GMCS_SOURCE + Expression e = ExplicitConversionCore (ec, expr, target_type, loc); + if (e != null) { + // + // Don't eliminate explicit precission casts + // + if (e == expr) { + if (target_type == TypeManager.float_type) + return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); + + if (target_type == TypeManager.double_type) + return new OpcodeCast (expr, target_type, OpCodes.Conv_R8); + } + + return e; + } + Type expr_type = expr.Type; if (TypeManager.IsNullableType (target_type)) { if (TypeManager.IsNullableType (expr_type)) { - e = new Nullable.LiftedConversion ( - expr, target_type, false, true, loc).Resolve (ec); - if (e != null) - return e; + Type target = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (target_type)[0]); + Expression unwrap = Nullable.Unwrap.Create (expr); + e = ExplicitConversion (ec, unwrap, target, expr.Location); + if (e == null) + return null; + + return new Nullable.Lifted (e, unwrap, target_type).Resolve (ec); } else if (expr_type == TypeManager.object_type) { return new UnboxCast (expr, target_type); } else { - Type target = TypeManager.GetTypeArguments (target_type) [0]; + Type target = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (target_type) [0]); e = ExplicitConversionCore (ec, expr, target, loc); if (e != null) return Nullable.Wrap.Create (e, target_type); } } else if (TypeManager.IsNullableType (expr_type)) { - e = Nullable.Unwrap.Create (expr, ec); + e = Nullable.Unwrap.Create (expr, false); bool use_class_cast; if (ImplicitBoxingConversionExists (e, target_type, out use_class_cast)) return new BoxedCast (expr, target_type); - e = ExplicitConversion (ec, e, target_type, loc); + e = ExplicitConversionCore (ec, e, target_type, loc); if (e != null) - e = EmptyCast.Create (e, target_type); - return e; + return EmptyCast.Create (e, target_type); } -#endif - e = ExplicitConversionCore (ec, expr, target_type, loc); - if (e != null) - return e; e = ExplicitUserConversion (ec, expr, target_type, loc); if (e != null)