X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fconvert.cs;h=5a1ebe831644b3503fed44d4b0f3eacdf4a1a14e;hb=21dd2b0200d091c43fce9e1941e8ab5e111f3651;hp=6c17437dd855e97ef5300a9d6092d74f13eb0c5d;hpb=db823064b80f2b73234d2b2e97a329dd49232330;p=mono.git diff --git a/mcs/mcs/convert.cs b/mcs/mcs/convert.cs index 6c17437dd85..5a1ebe83164 100644 --- a/mcs/mcs/convert.cs +++ b/mcs/mcs/convert.cs @@ -10,253 +10,177 @@ // 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 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 (); } - - static Type TypeParam_EffectiveBaseType (GenericConstraints gc) + + public static void Reset () { - ArrayList list = new ArrayList (); - list.Add (gc.EffectiveBaseClass); - foreach (Type t in gc.InterfaceConstraints) { - if (!TypeManager.IsGenericParameter (t)) - continue; - - GenericConstraints new_gc = TypeManager.GetTypeParameterConstraints (t); - if (new_gc != null) - list.Add (TypeParam_EffectiveBaseType (new_gc)); - } - return FindMostEncompassedType (list); + MyEmptyExpr = null; } -#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 ArrayToIList (ArrayContainer array, TypeSpec list, bool isExplicit) { -#if GMCS_SOURCE - if (!array.IsArray || (array.GetArrayRank () != 1) || !list.IsGenericType) + if (array.Rank != 1 || !list.IsGeneric) return false; - Type gt = list.GetGenericTypeDefinition (); - if ((gt != TypeManager.generic_ilist_type) && - (gt != TypeManager.generic_icollection_type) && - (gt != TypeManager.generic_ienumerable_type)) + var open_version = list.GetDefinition (); + if ((open_version != TypeManager.generic_ilist_type) && + (open_version != TypeManager.generic_icollection_type) && + (open_version != TypeManager.generic_ienumerable_type)) return false; - Type element_type = TypeManager.GetElementType (array); - Type arg_type = TypeManager.GetTypeArguments (list) [0]; - - if (element_type == arg_type) + var arg_type = list.TypeArguments[0]; + if (array.Element == arg_type) return true; + if (isExplicit) + return ExplicitReferenceConversionExists (array.Element, arg_type); + if (MyEmptyExpr == null) - MyEmptyExpr = new EmptyExpression (); - MyEmptyExpr.SetType (TypeManager.GetElementType (array)); + MyEmptyExpr = new EmptyExpression (array.Element); + else + MyEmptyExpr.SetType (array.Element); - return ImplicitReferenceConversionCore (MyEmptyExpr, arg_type); -#else - return false; -#endif + return ImplicitReferenceConversionExists (MyEmptyExpr, arg_type); } - static bool IList_To_Array(Type list, Type array) + static bool IList_To_Array(TypeSpec list, ArrayContainer array) { -# if GMCS_SOURCE - if (!list.IsGenericType || !array.IsArray || array.GetArrayRank() != 1) + if (array.Rank != 1 || !list.IsGeneric) return false; - - Type gt = list.GetGenericTypeDefinition(); - if (gt != TypeManager.generic_ilist_type && - gt != TypeManager.generic_icollection_type && - gt != TypeManager.generic_ienumerable_type) + + var open_version = list.GetDefinition (); + if ((open_version != TypeManager.generic_ilist_type) && + (open_version != TypeManager.generic_icollection_type) && + (open_version != TypeManager.generic_ienumerable_type)) return false; - - Type arg_type = TypeManager.GetTypeArguments(list)[0]; - Type element_type = TypeManager.GetElementType(array); - - if (element_type == arg_type) + + var arg_type = list.TypeArguments[0]; + if (array.Element == arg_type) return true; if (MyEmptyExpr == null) - MyEmptyExpr = new EmptyExpression(); - MyEmptyExpr.SetType(element_type); - return ImplicitReferenceConversionExists(MyEmptyExpr, arg_type) || ExplicitReferenceConversionExists(element_type, arg_type); -#else - return false; -#endif + MyEmptyExpr = new EmptyExpression (array.Element); + else + MyEmptyExpr.SetType (array.Element); + + return ImplicitReferenceConversionExists (MyEmptyExpr, arg_type) || ExplicitReferenceConversionExists (array.Element, arg_type); } - static Expression ImplicitTypeParameterConversion (Expression expr, - Type target_type) + static Expression ImplicitTypeParameterConversion (Expression expr, TypeSpec target_type) { -#if GMCS_SOURCE - Type expr_type = expr.Type; + var expr_type = (TypeParameterSpec) expr.Type; - GenericConstraints gc = TypeManager.GetTypeParameterConstraints (expr_type); + // + // From T to a type parameter U, provided T depends on U + // + var ttype = target_type as TypeParameterSpec; + if (ttype != null) { + if (expr_type.TypeArguments != null) { + foreach (var targ in expr_type.TypeArguments) { + if (!TypeSpecComparer.Override.IsEqual (ttype, targ)) + continue; - if (gc == null) { - if (target_type == TypeManager.object_type) - return new BoxedCast (expr, target_type); + if (expr_type.IsReferenceType && !ttype.IsReferenceType) + return new BoxedCast (expr, target_type); + + return new ClassCast (expr, target_type); + } + } return null; } - // We're converting from a type parameter which is known to be a reference type. - Type base_type = TypeParam_EffectiveBaseType (gc); - - if (TypeManager.IsSubclassOf (base_type, target_type)) - return new ClassCast (expr, target_type); - - if (target_type.IsInterface) { - if (TypeManager.ImplementsInterface (base_type, target_type)) + // + // LAMESPEC: From T to dynamic type + // + if (target_type == InternalType.Dynamic) { + if (expr_type.IsReferenceType) return new ClassCast (expr, target_type); - foreach (Type t in gc.InterfaceConstraints) { - if (TypeManager.IsSubclassOf (t, target_type)) - return new ClassCast (expr, target_type); - if (TypeManager.ImplementsInterface (t, target_type)) - return new ClassCast (expr, target_type); - } + return new BoxedCast (expr, target_type); } - foreach (Type t in gc.InterfaceConstraints) { - if (!TypeManager.IsGenericParameter (t)) - continue; - if (TypeManager.IsSubclassOf (t, target_type)) - return new ClassCast (expr, target_type); - if (TypeManager.ImplementsInterface (t, target_type)) + // + // From T to its effective base class C + // From T to any base class of C + // From T to any interface implemented by C + // + var base_type = expr_type.GetEffectiveBase (); + if (base_type == target_type || TypeManager.IsSubclassOf (base_type, target_type) || base_type.ImplementsInterface (target_type)) { + if (expr_type.IsReferenceType) 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) { - use_class_cast = false; - return target_type == TypeManager.object_type; + return new BoxedCast (expr, target_type); } - use_class_cast = true; - - if (!gc.HasReferenceTypeConstraint) - return false; - - // We're converting from a type parameter which is known to be a reference type. - Type base_type = TypeParam_EffectiveBaseType (gc); - - if (TypeManager.IsSubclassOf (base_type, target_type)) - return true; - - if (target_type.IsInterface) { - if (TypeManager.ImplementsInterface (base_type, target_type)) - return true; - - foreach (Type t in gc.InterfaceConstraints) { - if (TypeManager.IsSubclassOf (t, target_type)) - return true; - if (TypeManager.ImplementsInterface (t, target_type)) - return true; - } - } + if (target_type.IsInterface && expr_type.IsConvertibleToInterface (target_type)) { + if (expr_type.IsReferenceType) + return new ClassCast (expr, target_type); - foreach (Type t in gc.InterfaceConstraints) { - if (!TypeManager.IsGenericParameter (t)) - continue; - if (TypeManager.IsSubclassOf (t, target_type)) - return true; - if (TypeManager.ImplementsInterface (t, target_type)) - return true; + return new BoxedCast (expr, target_type); } -#endif - use_class_cast = false; - return false; + return null; } - static bool ExplicitTypeParameterConversionExists (Type source_type, Type target_type) + static Expression ExplicitTypeParameterConversion (Expression source, TypeSpec source_type, TypeSpec target_type) { -#if GMCS_SOURCE - if (TypeManager.IsGenericParameter (target_type)) { - GenericConstraints gc = TypeManager.GetTypeParameterConstraints (target_type); - if (gc == null) - return false; - - foreach (Type iface in gc.InterfaceConstraints) { - if (!TypeManager.IsGenericParameter (iface)) - continue; + var target_tp = target_type as TypeParameterSpec; + if (target_tp != null) { + if (target_tp.TypeArguments != null) { + foreach (var targ in target_tp.TypeArguments) { + if (!TypeSpecComparer.Override.IsEqual (source_type, targ)) + continue; - if (TypeManager.IsSubclassOf (source_type, iface)) - return true; + return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); + } } - } -#endif - return target_type.IsInterface; - } - static Expression ExplicitTypeParameterConversion (Expression source, Type target_type) - { -#if GMCS_SOURCE - Type source_type = source.Type; - - 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 (target_tp.Interfaces != null) { + foreach (TypeSpec iface in target_tp.Interfaces) { + if (!TypeManager.IsGenericParameter (iface)) + continue; - if (TypeManager.IsSubclassOf (source_type, iface)) - return new ClassCast (source, target_type); + if (TypeManager.IsSubclassOf (source_type, iface)) + return source == null ? EmptyExpression.Null : new ClassCast (source, target_type, true); + } } + + return null; } if (target_type.IsInterface) - return new ClassCast (source, target_type); -#endif + return source == null ? EmptyExpression.Null : new ClassCast (source, target_type, true); + return null; } - static EmptyExpression MyEmptyExpr; - static Expression ImplicitReferenceConversion (Expression expr, Type target_type, bool explicit_cast) + static Expression ImplicitReferenceConversion (Expression expr, TypeSpec target_type, bool explicit_cast) { - Type expr_type = expr.Type; + TypeSpec expr_type = expr.Type; if (expr_type == null && expr.eclass == ExprClass.MethodGroup){ // if we are a method group, emit a warning @@ -267,7 +191,7 @@ namespace Mono.CSharp { if (expr_type == TypeManager.void_type) return null; - if (TypeManager.IsGenericParameter (expr_type)) + if (expr_type.Kind == MemberKind.TypeParameter) return ImplicitTypeParameterConversion (expr, target_type); // @@ -275,39 +199,56 @@ 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)) { // - // Reduce implicit reference conversion to object + // Avoid wrapping implicitly convertible reference type // - if (!explicit_cast && target_type == TypeManager.object_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)) { - if (use_class_cast) - return new ClassCast (expr, target_type); - else - return new BoxedCast (expr, target_type); - } - - return null; + return ImplicitBoxingConversion (expr, expr_type, target_type); } - static public bool ImplicitReferenceConversionCore (Expression expr, Type target_type) + // + // 6.1.6 Implicit reference conversions + // + public static bool ImplicitReferenceConversionExists (Expression expr, TypeSpec target_type) { - Type expr_type = expr.Type; + if (TypeManager.IsStruct (target_type)) + return false; + + TypeSpec 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; + + // 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 any class-type S to any interface-type T. + if (target_type.IsInterface) { + if (expr_type.ImplementsInterface (target_type)){ + return !TypeManager.IsValueType (expr_type); + } + } // // 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 || target_type == InternalType.Dynamic) { // // A pointer type cannot be converted to object // @@ -316,10 +257,20 @@ 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; + + if (expr_type.IsClass || expr_type.IsInterface || expr_type == TypeManager.enum_type || expr_type.IsDelegate || expr_type.Kind == MemberKind.ArrayType) { + // No mcs internal types are convertible + return true; // expr_type.MetaInfo.Module != typeof (Convert).Module; } + // From anything to dynamic + if (target_type == InternalType.Dynamic) + return true; + + // From dynamic to object + if (expr_type == InternalType.Dynamic) + return true; + return false; } else if (target_type == TypeManager.value_type) { return expr_type == TypeManager.enum_type; @@ -331,109 +282,134 @@ namespace Mono.CSharp { // if (target_type == TypeManager.enum_type || TypeManager.IsGenericParameter (expr_type)) return false; - - return true; - } - // 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 + if (TypeManager.IsValueType (expr_type)) + return false; - // from any class-type S to any interface-type T. - if (target_type.IsInterface) { - if (TypeManager.ImplementsInterface (expr_type, target_type)){ - return !TypeManager.IsGenericParameter (expr_type) && - !TypeManager.IsValueType (expr_type); - } - } + // Array type variance conversion + //if (target_type.IsArray != expr_type.IsArray) + // return false; - // from any interface type S to interface-type T. - if (expr_type.IsInterface && target_type.IsInterface) { - return 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 ()) { + var expr_type_array = expr_type as ArrayContainer; + if (expr_type_array != null) { + var target_type_array = target_type as ArrayContainer; + // from an array-type S to an array-type of type T + if (target_type_array != null && expr_type_array.Rank == target_type_array.Rank) { - Type expr_element_type = TypeManager.GetElementType (expr_type); + // + // Both SE and TE are reference-types + // + TypeSpec expr_element_type = expr_type_array.Element; + if (!TypeManager.IsReferenceType (expr_element_type)) + return false; - if (MyEmptyExpr == null) - MyEmptyExpr = new EmptyExpression (); + TypeSpec target_element_type = target_type_array.Element; + if (!TypeManager.IsReferenceType (target_element_type)) + return false; - MyEmptyExpr.SetType (expr_element_type); - Type target_element_type = TypeManager.GetElementType (target_type); + if (MyEmptyExpr == null) + MyEmptyExpr = new EmptyExpression (expr_element_type); + else + MyEmptyExpr.SetType (expr_element_type); - if (!expr_element_type.IsValueType && !target_element_type.IsValueType) - return ImplicitStandardConversionExists ( - MyEmptyExpr, target_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 (ArrayToIList (expr_type_array, target_type, false)) + return true; + + return false; } - // from an array-type to System.Array - if (expr_type.IsArray && target_type == TypeManager.array_type) + if (TypeSpecComparer.Variant.IsEqual (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 expr_type.ImplementsInterface (target_type); + } // from any delegate type to System.Delegate if (target_type == TypeManager.delegate_type && - (expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type))) + (expr_type == TypeManager.delegate_type || expr_type.IsDelegate)) 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, - out bool use_class_cast) + public static Expression ImplicitBoxingConversion (Expression expr, TypeSpec expr_type, TypeSpec target_type) { - Type expr_type = expr.Type; - use_class_cast = false; - // // From any value-type to the type object. // - if (target_type == TypeManager.object_type) { + if (target_type == TypeManager.object_type || target_type == InternalType.Dynamic) { // // A pointer type cannot be converted to object // if (expr_type.IsPointer) - return false; + return null; + + if (!TypeManager.IsValueType (expr_type)) + return null; - return TypeManager.IsValueType (expr_type); + return expr == null ? EmptyExpression.Null : new BoxedCast (expr, target_type); } // // From any value-type to the type System.ValueType. // - if (target_type == TypeManager.value_type) - return TypeManager.IsValueType (expr_type); + if (target_type == TypeManager.value_type) { + if (!TypeManager.IsValueType (expr_type)) + return null; + + return expr == null ? EmptyExpression.Null : new BoxedCast (expr, target_type); + } if (target_type == TypeManager.enum_type) { // // From any enum-type to the type System.Enum. // - if (expr_type.IsEnum) - 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; + if (TypeManager.IsEnumType (expr_type)) + return expr == null ? EmptyExpression.Null : new BoxedCast (expr, target_type); } - + + // + // From a nullable-type to a reference type, if a boxing conversion exists from + // the underlying type to the reference type + // + if (TypeManager.IsNullableType (expr_type)) { + if (!TypeManager.IsReferenceType (target_type)) + return null; + + var res = ImplicitBoxingConversion (expr, Nullable.NullableInfo.GetUnderlyingType (expr_type), target_type); + + // "cast" underlying type to target type to emit correct InvalidCastException when + // underlying hierarchy changes without recompilation + if (res != null && expr != null) + res = new UnboxCast (res, target_type); + + return res; + } + if (TypeManager.IsSubclassOf (expr_type, target_type)) { - if (TypeManager.IsGenericParameter (expr_type)) - return true; + // + // Don't box same type arguments + // + if (TypeManager.IsGenericParameter (expr_type) && expr_type != target_type) + return expr == null ? EmptyExpression.Null : new BoxedCast (expr, target_type); - return false; + return null; } // This code is kind of mirrored inside ImplicitStandardConversionExists @@ -443,43 +419,69 @@ namespace Mono.CSharp { // from any class-type S to any interface-type T. if (target_type.IsInterface) { - if (TypeManager.ImplementsInterface (expr_type, target_type)) - return TypeManager.IsGenericParameter (expr_type) || - TypeManager.IsValueType (expr_type); + if (expr_type.ImplementsInterface (target_type) && + (TypeManager.IsGenericParameter (expr_type) || TypeManager.IsValueType (expr_type))) { + return expr == null ? EmptyExpression.Null : new BoxedCast (expr, target_type); + } } - if (TypeManager.IsGenericParameter (expr_type)) - return ImplicitTypeParameterBoxingConversion ( - expr_type, target_type, out use_class_cast); - - return false; + return null; } - // - // 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, TypeSpec target_type) { - if (target_type.IsValueType) - return false; + TypeSpec expr_type = expr.Type; + + // + // From null to any nullable type + // + if (expr_type == TypeManager.null_type) + return ec == null ? EmptyExpression.Null : Nullable.LiftedNull.Create (target_type, expr.Location); - Type expr_type = expr.Type; + // S -> T? + TypeSpec t_el = Nullable.NullableInfo.GetUnderlyingType (target_type); - // from the null type to any reference-type. - if (expr_type == TypeManager.null_type){ - return target_type != TypeManager.anonymous_method_type; + // S? -> T? + if (TypeManager.IsNullableType (expr_type)) + expr_type = Nullable.NullableInfo.GetUnderlyingType (expr_type); + + // + // Predefined implicit identity or implicit numeric conversion + // has to exist between underlying type S and underlying type T + // + + // conversion exists only mode + if (ec == null) { + if (expr_type == t_el) + return EmptyExpression.Null; + + if (expr is Constant) + return ((Constant) expr).ConvertImplicitly (ec, t_el); + + 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 = unwrap; + if (expr_type != t_el) { + if (conv is Constant) + conv = ((Constant)conv).ConvertImplicitly (ec, t_el); + else + conv = ImplicitNumericConversion (conv, expr_type, t_el); - return false; + if (conv == null) + return null; + } + + if (expr_type != expr.Type) + return new Nullable.Lifted (conv, unwrap, target_type).Resolve (ec); + + return Nullable.Wrap.Create (conv, target_type); } /// @@ -488,153 +490,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, TypeSpec 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, TypeSpec expr_type, TypeSpec 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.int32_type || real_target_type == TypeManager.uint32_type || - real_target_type == TypeManager.short_type || real_target_type == TypeManager.ushort_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.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) + 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.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.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; @@ -644,35 +643,30 @@ 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, TypeSpec 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; - if (expr.Type == TypeManager.anonymous_method_type) { - if (!TypeManager.IsDelegateType (target_type) && - TypeManager.DropGenericTypeArguments (target_type) != TypeManager.expression_type) + if (expr.Type == InternalType.AnonymousMethod) { + if (!TypeManager.IsDelegateType (target_type) && target_type.GetDefinition () != TypeManager.expression_type) return false; AnonymousMethodExpression ame = (AnonymousMethodExpression) expr; return ame.ImplicitStandardConversionExists (ec, target_type); } + + if (expr.eclass == ExprClass.MethodGroup) { + if (target_type.IsDelegate && RootContext.Version != LanguageVersion.ISO_1) { + MethodGroupExpr mg = expr as MethodGroupExpr; + if (mg != null) + return DelegateCreation.ImplicitStandardConversionExists (ec, mg, target_type); + } - return ImplicitUserConversion (ec, expr, target_type, Location.Null) != null; - } + return false; + } - public static bool ImplicitUserConversionExists (EmitContext ec, Type source, Type target) - { - return ImplicitUserConversion (ec, new EmptyExpression (source), target, Location.Null) != null; + return ImplicitUserConversion (ec, expr, target_type, Location.Null) != null; } /// @@ -681,153 +675,36 @@ namespace Mono.CSharp { /// /// ec should point to a real EmitContext if expr.Type is TypeManager.anonymous_method_type. /// - public static bool ImplicitStandardConversionExists (Expression expr, Type target_type) + public static bool ImplicitStandardConversionExists (Expression expr, TypeSpec 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]; + TypeSpec expr_type = expr.Type; - // 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; - } - } - - return false; - } + // First numeric conversions + if (ImplicitNumericConversion (null, expr_type, target_type) != null) + return true; if (ImplicitReferenceConversionExists (expr, target_type)) return true; + if (ImplicitBoxingConversion (null, expr_type, target_type) != null) + return true; + // // Implicit Constant Expression Conversions // @@ -858,9 +735,6 @@ namespace Mono.CSharp { if (value >= 0) return true; } - - if (value == 0 && expr is IntLiteral && TypeManager.IsEnumType (target_type)) - return true; } if (expr is LongConstant && target_type == TypeManager.uint64_type){ @@ -874,36 +748,45 @@ namespace Mono.CSharp { return true; } + if (expr is IntegralConstant && TypeManager.IsEnumType (target_type)) { + var i = (IntegralConstant) expr; + // + // LAMESPEC: csc allows any constant like 0 values to be converted, including const float f = 0.0 + // + // 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 + // + return i.IsZeroInteger; + } + // // 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 && expr_type.ImplementsInterface (target_type)) return true; if (target_type == TypeManager.void_ptr_type && expr_type.IsPointer) return true; + // Conversion from __arglist to System.ArgIterator + if (expr_type == InternalType.Arglist) + return target_type == TypeManager.arg_iterator_type; + return false; } /// - /// Finds "most encompassed type" according to the spec (13.4.2) - /// amongst the methods in the MethodGroupExpr - /// - static Type FindMostEncompassedType (ArrayList types) - { - Type best = null; - - if (types.Count == 0) - return null; - - if (types.Count == 1) - return (Type) types [0]; - + /// Finds "most encompassed type" according to the spec (13.4.2) + /// amongst the methods in the MethodGroupExpr + /// + public static TypeSpec FindMostEncompassedType (IEnumerable types) + { + TypeSpec best = null; EmptyExpression expr = EmptyExpression.Grab (); - foreach (Type t in types) { + foreach (TypeSpec t in types) { if (best == null) { best = t; continue; @@ -915,7 +798,7 @@ namespace Mono.CSharp { } expr.SetType (best); - foreach (Type t in types) { + foreach (TypeSpec t in types) { if (best == t) continue; if (!ImplicitStandardConversionExists (expr, t)) { @@ -933,19 +816,19 @@ 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 TypeSpec FindMostEncompassingType (IList types) { - Type best = null; + TypeSpec best = null; if (types.Count == 0) return null; if (types.Count == 1) - return (Type) types [0]; + return types [0]; EmptyExpression expr = EmptyExpression.Grab (); - foreach (Type t in types) { + foreach (TypeSpec t in types) { if (best == null) { best = t; continue; @@ -956,7 +839,7 @@ namespace Mono.CSharp { best = t; } - foreach (Type t in types) { + foreach (TypeSpec t in types) { if (best == t) continue; expr.SetType (t); @@ -976,18 +859,17 @@ 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 TypeSpec 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); + TypeSpec source_type = source.Type; + foreach (var mb in list){ + TypeSpec param_type = mb.Parameters.Types [0]; if (param_type == source_type) return param_type; @@ -999,9 +881,9 @@ 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){ + foreach (TypeSpec param_type in src_types_set){ if (ImplicitStandardConversionExists (source, param_type)) candidate_set.Add (param_type); } @@ -1022,16 +904,16 @@ namespace Mono.CSharp { /// /// Finds the most specific target Tx according to section 13.4.4 /// - static public Type FindMostSpecificTarget (IList list, - Type target, bool apply_explicit_conv_rules) + static public TypeSpec FindMostSpecificTarget (IList list, + TypeSpec 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 // - foreach (MethodInfo mi in list){ - Type ret_type = TypeManager.TypeToCoreType (mi.ReturnType); + foreach (var mi in list){ + TypeSpec ret_type = mi.ReturnType; if (ret_type == target) return ret_type; @@ -1042,11 +924,11 @@ 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 (); - foreach (Type ret_type in tgt_types_set){ + foreach (TypeSpec ret_type in tgt_types_set){ expr.SetType (ret_type); if (ImplicitStandardConversionExists (expr, target)) @@ -1071,190 +953,210 @@ namespace Mono.CSharp { /// /// User-defined Implicit conversions /// - static public Expression ImplicitUserConversion (EmitContext ec, Expression source, - Type target, Location loc) + static public Expression ImplicitUserConversion (ResolveContext ec, Expression source, TypeSpec target, Location loc) { - Expression expr = UserDefinedConversion (ec, source, target, loc, false); - if (expr != null && !TypeManager.IsEqual (expr.Type, target)) - expr = ImplicitConversionStandard (ec, expr, target, loc); - - return expr; + return UserDefinedConversion (ec, source, target, true, loc); } /// /// User-defined Explicit conversions /// - static public Expression ExplicitUserConversion (EmitContext ec, Expression source, - Type target, Location loc) + static Expression ExplicitUserConversion (ResolveContext ec, Expression source, TypeSpec target, Location loc) { - Expression expr = UserDefinedConversion (ec, source, target, loc, true); - if (expr != null && !TypeManager.IsEqual (expr.Type, target)) - expr = ExplicitConversionStandard (ec, expr, target, loc); - - return expr; + return UserDefinedConversion (ec, source, target, false, loc); } - static void AddConversionOperators (ArrayList list, - Expression source, Type target_type, - bool look_for_explicit, - MethodGroupExpr mg) + static void FindApplicableUserDefinedConversionOperators (IList operators, Expression source, TypeSpec target, bool implicitOnly, ref List candidates) { - if (mg == null) - return; - - 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; + if (source.Type == TypeManager.intptr_type) { + if (target == TypeManager.uint32_type) + target = TypeManager.int32_type; + } else if (source.Type == TypeManager.uintptr_type) { + if (target == TypeManager.int64_type) + target = TypeManager.uint64_type; } - foreach (MethodInfo m in mg.Methods) { - ParameterData pd = TypeManager.GetParameterData (m); - Type return_type = TypeManager.TypeToCoreType (m.ReturnType); - Type arg_type = pd.ParameterType (0); + // For a conversion operator to be applicable, it must be possible + // to perform a standard conversion from the source type to + // the operand type of the operator, and it must be possible + // to perform a standard conversion from the result type of + // the operator to the target type. - if (source_type != arg_type) { - if (!ImplicitStandardConversionExists (source, arg_type)) { - if (!look_for_explicit) - continue; - expr.SetType (arg_type); - if (!ImplicitStandardConversionExists (expr, source_type)) - continue; - } - } + Expression texpr = null; - if (target_type != return_type) { - expr.SetType (return_type); - if (!ImplicitStandardConversionExists (expr, target_type)) { - if (!look_for_explicit) - continue; - expr.SetType (target_type); - if (!ImplicitStandardConversionExists (expr, return_type)) - continue; - } + foreach (MethodSpec op in operators) { + + // Can be null because MemberCache.GetUserOperator does not resize the array + if (op == null) + continue; + + var t = op.Parameters.Types[0]; + if (source.Type != t && !ImplicitStandardConversionExists (source, t)) { + if (implicitOnly) + continue; + + if (!ImplicitStandardConversionExists (new EmptyExpression (t), source.Type)) + continue; } - // See LAMESPEC: Exclude IntPtr -> int conversion - if (source_type == TypeManager.uintptr_type && return_type == TypeManager.uint32_type) + t = op.ReturnType; + + // LAMESPEC: Exclude UIntPtr -> int conversion + if (t == TypeManager.uint32_type && source.Type == TypeManager.uintptr_type) continue; - list.Add (m); - } + if (target != t && !ImplicitStandardConversionExists (new EmptyExpression (t), target)) { + if (implicitOnly) + continue; - EmptyExpression.Release (expr); + if (texpr == null) + texpr = new EmptyExpression (target); + + if (!ImplicitStandardConversionExists (texpr, t)) + continue; + } + + if (candidates == null) + candidates = new List (); + + candidates.Add (op); + } } - /// - /// 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) + // + // User-defined conversions + // + static Expression UserDefinedConversion (ResolveContext ec, Expression source, TypeSpec target, bool implicitOnly, Location loc) { - ArrayList ops = new ArrayList (4); + List candidates = null; - Type source_type = source.Type; + // + // If S or T are nullable types, S0 and T0 are their underlying types + // otherwise S0 and T0 are equal to S and T respectively. + // + TypeSpec source_type = source.Type; + TypeSpec target_type = target; + Expression unwrap; - 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); - if (look_for_explicit) { - AddConversionOperators (ops, source, target_type, look_for_explicit, - Expression.MethodLookup ( - container_type, source_type, "op_Explicit", Location.Null) as MethodGroupExpr); - } - } + if (TypeManager.IsNullableType (source_type)) { + // No implicit conversion S? -> T for non-reference types + if (implicitOnly && !TypeManager.IsReferenceType (target_type) && !TypeManager.IsNullableType (target_type)) + return null; - 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); - if (look_for_explicit) { - AddConversionOperators (ops, source, target_type, look_for_explicit, - Expression.MethodLookup ( - container_type, target_type, "op_Explicit", Location.Null) as MethodGroupExpr); - } + unwrap = source = Nullable.Unwrap.Create (source); + source_type = source.Type; + } else { + unwrap = null; } - if (ops.Count == 0) - return null; + if (TypeManager.IsNullableType (target_type)) + target_type = Nullable.NullableInfo.GetUnderlyingType (target_type); - Type most_specific_source = FindMostSpecificSource (ops, source, look_for_explicit); - if (most_specific_source == null) - return null; + // Only these containers can contain a user defined implicit or explicit operators + const MemberKind user_conversion_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.TypeParameter; - Type most_specific_target = FindMostSpecificTarget (ops, target_type, look_for_explicit); - if (most_specific_target == null) - return null; + if ((source_type.Kind & user_conversion_kinds) != 0 && source_type != TypeManager.decimal_type) { + bool declared_only = source_type.IsStruct; - MethodInfo method = null; + var operators = MemberCache.GetUserOperator (source_type, Operator.OpType.Implicit, declared_only); + if (operators != null) { + FindApplicableUserDefinedConversionOperators (operators, source, target_type, implicitOnly, ref candidates); + } - foreach (MethodInfo m in ops) { - if (TypeManager.TypeToCoreType (m.ReturnType) != most_specific_target) - continue; - if (TypeManager.GetParameterData (m).ParameterType (0) != most_specific_source) - continue; - // Ambiguous: more than one conversion operator satisfies the signature. - if (method != null) - return null; - method = m; + if (!implicitOnly) { + operators = MemberCache.GetUserOperator (source_type, Operator.OpType.Explicit, declared_only); + if (operators != null) { + FindApplicableUserDefinedConversionOperators (operators, source, target_type, false, ref candidates); + } + } } - return method; - } + if ((target.Kind & user_conversion_kinds) != 0 && target != TypeManager.decimal_type) { + bool declared_only = target.IsStruct || implicitOnly; - static DoubleHash explicit_conv = new DoubleHash (100); - static DoubleHash implicit_conv = new DoubleHash (100); + var operators = MemberCache.GetUserOperator (target_type, Operator.OpType.Implicit, declared_only); + if (operators != null) { + FindApplicableUserDefinedConversionOperators (operators, source, target_type, implicitOnly, ref candidates); + } - /// - /// User-defined conversions - /// - static public Expression UserDefinedConversion (EmitContext ec, Expression source, - Type target, Location loc, - bool look_for_explicit) - { - Type source_type = source.Type; - MethodInfo method = null; + if (!implicitOnly) { + operators = MemberCache.GetUserOperator (target_type, Operator.OpType.Explicit, declared_only); + if (operators != null) { + FindApplicableUserDefinedConversionOperators (operators, source, target_type, false, ref candidates); + } + } + } - object o; - DoubleHash hash = look_for_explicit ? explicit_conv : implicit_conv; + if (candidates == null) + return null; - if (!(source is Constant) && hash.Lookup (source_type, target, out o)) { - method = (MethodInfo) o; + // + // Find the most specific conversion operator + // + MethodSpec most_specific_operator; + TypeSpec s_x, t_x; + if (candidates.Count == 1) { + most_specific_operator = candidates[0]; + s_x = most_specific_operator.Parameters.Types[0]; + t_x = most_specific_operator.ReturnType; } else { - method = GetConversionOperator (null, source, target, look_for_explicit); - if (!(source is Constant)) - hash.Insert (source_type, target, method); + s_x = FindMostSpecificSource (candidates, source, !implicitOnly); + if (s_x == null) + return null; + + t_x = FindMostSpecificTarget (candidates, target, !implicitOnly); + if (t_x == null) + return null; + + most_specific_operator = candidates[0]; + + for (int i = 1; i < candidates.Count; ++i) { + if (candidates[i].ReturnType == t_x && candidates[i].Parameters.Types[0] == s_x) { + most_specific_operator = candidates[i]; + break; + } + } } - if (method == null) - return null; + // + // Convert input type when it's different to best operator argument + // + if (s_x != source.Type) + source = implicitOnly ? + ImplicitConversionStandard (ec, source, s_x, loc) : + ExplicitConversionStandard (ec, source, s_x, loc); - Type most_specific_source = TypeManager.GetParameterData (method).ParameterType (0); + source = new UserCast (most_specific_operator, source, loc).Resolve (ec); // - // 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. + // Convert result type when it's different to best operator return type // - if (look_for_explicit) - source = ExplicitConversionStandard (ec, source, most_specific_source, loc); - else - source = ImplicitConversionStandard (ec, source, most_specific_source, loc); + if (t_x != target_type) { + // + // User operator is of T?, no need to lift it + // + if (TypeManager.IsNullableType (t_x) && t_x == target) + return source; - if (source == null) - return null; + source = implicitOnly ? + ImplicitConversionStandard (ec, source, target_type, loc) : + ExplicitConversionStandard (ec, source, target_type, loc); + } - return new UserCast (method, source, loc); + // + // Source expression is of nullable type, lift the result in case of it's null + // + if (unwrap != null && (TypeManager.IsReferenceType (target) || target_type != target)) + source = new Nullable.Lifted (source, unwrap, target).Resolve (ec); + else if (target_type != target) + source = Nullable.Wrap.Create (source, target); + + return source; } /// @@ -1262,8 +1164,8 @@ 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, - Type target_type, Location loc) + static public Expression ImplicitConversion (ResolveContext ec, Expression expr, + TypeSpec target_type, Location loc) { Expression e; @@ -1292,41 +1194,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, - Type target_type, Location loc) + static public Expression ImplicitConversionStandard (ResolveContext ec, Expression expr, + TypeSpec target_type, Location loc) { return ImplicitConversionStandard (ec, expr, target_type, loc, false); } - static Expression ImplicitConversionStandard (EmitContext ec, Expression expr, Type target_type, Location loc, bool explicit_cast) + static Expression ImplicitConversionStandard (ResolveContext ec, Expression expr, TypeSpec target_type, Location loc, bool explicit_cast) { - 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]; - - if (TypeManager.IsNullableType (expr_type)) { - Type etype = TypeManager.GetTypeArguments (expr_type) [0]; - if (TypeManager.IsEqual (etype, target)) - return expr; - - return new Nullable.LiftedConversion ( - expr, target_type, false, false, loc).Resolve (ec); - } else { - e = ImplicitConversion (ec, expr, target, loc); - if (e != null) - return Nullable.Wrap.Create (e, target_type); - } - } -#endif if (expr.eclass == ExprClass.MethodGroup){ if (!TypeManager.IsDelegateType (target_type)){ return null; @@ -1343,23 +1218,29 @@ namespace Mono.CSharp { } } - if (expr_type.Equals (target_type) && expr_type != TypeManager.null_type) + TypeSpec 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 (TypeSpecComparer.Variant.IsEqual (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; @@ -1368,7 +1249,7 @@ namespace Mono.CSharp { return c; } - e = ImplicitNumericConversion (expr, target_type); + e = ImplicitNumericConversion (expr, expr_type, target_type); if (e != null) return e; @@ -1376,14 +1257,22 @@ namespace Mono.CSharp { 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 IntegralConstant && TypeManager.IsEnumType (target_type)){ + var i = (IntegralConstant) expr; + // + // LAMESPEC: csc allows any constant like 0 values to be converted, including const float f = 0.0 + // + // 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.IsZeroInteger) { + // Recreate 0 literal to remove any collected conversions + return new EnumConstant (new IntLiteral (0, i.Location), 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); @@ -1401,16 +1290,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; } @@ -1419,13 +1311,19 @@ namespace Mono.CSharp { /// ImplicitConversion. If there is no implicit conversion, then /// an error is signaled /// - static public Expression ImplicitConversionRequired (EmitContext ec, Expression source, - Type target_type, Location loc) + static public Expression ImplicitConversionRequired (ResolveContext ec, Expression source, + TypeSpec target_type, Location loc) { Expression e = ImplicitConversion (ec, source, target_type, loc); if (e != null) return e; + if (source.Type == InternalType.Dynamic) { + 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; } @@ -1451,10 +1349,10 @@ namespace Mono.CSharp { /// Int16->UIntPtr /// /// - public static Expression ExplicitNumericConversion (Expression expr, Type target_type) + public static Expression ExplicitNumericConversion (Expression expr, TypeSpec target_type) { - Type expr_type = expr.Type; - Type real_target_type = target_type; + TypeSpec expr_type = expr.Type; + TypeSpec real_target_type = target_type; if (expr_type == TypeManager.sbyte_type){ // @@ -1704,223 +1602,144 @@ namespace Mono.CSharp { /// Returns whether an explicit reference conversion can be performed /// from source_type to target_type /// - public static bool ExplicitReferenceConversionExists (Type source_type, Type target_type) + public static bool ExplicitReferenceConversionExists (TypeSpec source_type, TypeSpec 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, TypeSpec source_type, TypeSpec target_type) { - Type source_type = source.Type; - bool target_is_type_param = TypeManager.IsGenericParameter (target_type); - bool target_is_value_type = target_type.IsValueType; - // // 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 (source_type.Kind == MemberKind.TypeParameter) + return ExplicitTypeParameterConversion (source, source_type, target_type); - if (TypeManager.IsGenericParameter (source_type)) - return ExplicitTypeParameterConversion (source, target_type); + bool target_is_value_type = TypeManager.IsStruct (target_type) || TypeManager.IsEnumType (target_type); // - // From object to any reference type + // Unboxing conversion from System.ValueType to any non-nullable-value-type // - if (source_type == TypeManager.object_type && !target_is_value_type) - return new ClassCast (source, target_type); + if (source_type == TypeManager.value_type && target_is_value_type) + return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type); // - // Unboxing conversion. + // From object to any reference type or value type (unboxing) // - if (((source_type == TypeManager.enum_type && - !(source is TypeCast)) || - source_type == TypeManager.value_type) && target_is_value_type) - return new UnboxCast (source, target_type); + if (source_type == TypeManager.object_type) + return + source == null ? EmptyExpression.Null : + target_is_value_type ? new UnboxCast (source, target_type) : + source is Constant ? (Expression) new EmptyConstantCast ((Constant) source, target_type) : + new ClassCast (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); - } - - // - // 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 (source_type.Kind == MemberKind.Class && TypeManager.IsSubclassOf (target_type, source_type)) + return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); // // 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) { - if (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)) { + if (!target_type.IsSealed || target_type.ImplementsInterface (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); } // - // From System.Collecitons.Generic.IList and its base interfaces to a one-dimensional + // From System.Collections.Generic.IList and its base interfaces to a one-dimensional // 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); + var target_array = target_type as ArrayContainer; + if (target_array != null && IList_To_Array (source_type, target_array)) + 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 ()) { + var source_array = source_type as ArrayContainer; + if (source_array != null) { + var target_array = target_type as ArrayContainer; + if (target_array != null) { + // + // From System.Array to any array-type + // + if (source_type == TypeManager.array_type) + return source == null ? EmptyExpression.Null : new ClassCast (source, 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_array.Rank == target_array.Rank) { - Type source_element_type = TypeManager.GetElementType (source_type); - Type target_element_type = TypeManager.GetElementType (target_type); + source_type = source_array.Element; + if (!TypeManager.IsReferenceType (source_type)) + return null; - if (!source_element_type.IsValueType && !target_element_type.IsValueType) - if (ExplicitReferenceConversionExists (source_element_type, - target_element_type)) - return new ClassCast (source, target_type); + var target_element = target_array.Element; + if (!TypeManager.IsReferenceType (target_element)) + return null; + + if (ExplicitReferenceConversionExists (source_type, target_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 (ArrayToIList (source_array, target_type, true)) + return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); + + return null; + } - // From System.Array to any array-type - if (source_type == TypeManager.array_type && - target_type.IsArray) { - return 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 && !source_type.ImplementsInterface (target_type)) { + return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); } // // 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; } @@ -1929,67 +1748,83 @@ 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, - Type target_type, Location loc) + static public Expression ExplicitConversionCore (ResolveContext ec, Expression expr, + TypeSpec target_type, Location loc) { - Type expr_type = expr.Type; + TypeSpec 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, 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); - if (expr != null) - return expr; + TypeSpec real_target = TypeManager.IsEnumType (target_type) ? EnumSpec.GetUnderlyingType (target_type) : target_type; + Expression underlying = EmptyCast.Create (expr, EnumSpec.GetUnderlyingType (expr_type)); + if (underlying.Type == real_target) + ne = underlying; + + if (ne == null) + ne = ImplicitNumericConversion (underlying, real_target); + + if (ne == null) + ne = ExplicitNumericConversion (underlying, real_target); + + // + // LAMESPEC: IntPtr and UIntPtr conversion to any Enum is allowed + // + if (ne == null && (real_target == TypeManager.intptr_type || real_target == TypeManager.uintptr_type)) + ne = ExplicitUserConversion (ec, underlying, real_target, loc); - return ExplicitUserConversion (ec, underlying, target_type, loc); + return ne != null ? EmptyCast.Create (ne, target_type) : null; } - if (TypeManager.IsEnumType (target_type)){ + if (TypeManager.IsEnumType (target_type)) { + // + // System.Enum can be unboxed to any enum-type + // if (expr_type == TypeManager.enum_type) return new UnboxCast (expr, target_type); - Expression ce = ExplicitConversionCore (ec, expr, TypeManager.GetEnumUnderlyingType (target_type), loc); - if (ce != null) - return EmptyCast.Create (ce, target_type); - + TypeSpec real_target = TypeManager.IsEnumType (target_type) ? EnumSpec.GetUnderlyingType (target_type) : target_type; + + if (expr_type == real_target) + return EmptyCast.Create (expr, target_type); + + ne = ImplicitNumericConversion (expr, real_target); + if (ne != null) + return EmptyCast.Create (ne, target_type); + + ne = ExplicitNumericConversion (expr, real_target); + if (ne != null) + return EmptyCast.Create (ne, target_type); + // // LAMESPEC: IntPtr and UIntPtr conversion to any Enum is allowed // - if (expr_type == TypeManager.intptr_type || expr_type == TypeManager.uintptr_type) { - ne = ExplicitUserConversion (ec, expr, TypeManager.GetEnumUnderlyingType (target_type), loc); + if (expr_type == TypeManager.intptr_type || expr_type == TypeManager.uintptr_type) { + ne = ExplicitUserConversion (ec, expr, real_target, loc); if (ne != null) return ExplicitConversionCore (ec, ne, target_type, loc); - } - - return null; + } + } else { + ne = ExplicitNumericConversion (expr, target_type); + if (ne != null) + return ne; } - ne = ExplicitNumericConversion (expr, target_type); - if (ne != null) - return ne; - // // Skip the ExplicitReferenceConversion because we can not convert // from Null to a ValueType, and ExplicitReference wont check against // 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; @@ -1998,9 +1833,9 @@ namespace Mono.CSharp { return null; } - public static Expression ExplicitUnsafe (Expression expr, Type target_type) + public static Expression ExplicitUnsafe (Expression expr, TypeSpec target_type) { - Type expr_type = expr.Type; + TypeSpec expr_type = expr.Type; if (target_type.IsPointer){ if (expr_type.IsPointer) @@ -2013,25 +1848,32 @@ namespace Mono.CSharp { if (expr_type == TypeManager.ushort_type || expr_type == TypeManager.uint32_type || - expr_type == TypeManager.uint64_type || expr_type == TypeManager.int64_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 || target_type == TypeManager.int64_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); } return null; @@ -2040,12 +1882,12 @@ namespace Mono.CSharp { /// /// Same as ExplicitConversion, only it doesn't include user defined conversions /// - static public Expression ExplicitConversionStandard (EmitContext ec, Expression expr, - Type target_type, Location l) + static public Expression ExplicitConversionStandard (ResolveContext ec, Expression expr, + TypeSpec 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) @@ -2055,11 +1897,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); @@ -2070,43 +1912,54 @@ 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, - Type target_type, Location loc) + static public Expression ExplicitConversion (ResolveContext ec, Expression expr, + TypeSpec target_type, Location loc) { - Expression e; -#if GMCS_SOURCE - Type expr_type = expr.Type; + 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; + } + + TypeSpec 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; + TypeSpec target = Nullable.NullableInfo.GetUnderlyingType (target_type); + 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]; + TypeSpec target = 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 = ImplicitBoxingConversion (expr, Nullable.NullableInfo.GetUnderlyingType (expr_type), target_type); + if (e != null) + return e; - 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 = Nullable.Unwrap.Create (expr, false); + 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)