X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fconvert.cs;h=ed8e103cd77c1cd4c860b5f298cefefc81303fde;hb=2f5f1984ec98936465970a2c0ddec4f085f02b24;hp=e442472283f97c709fb7455938d2f95f54b3a9f6;hpb=4302b6367d266ffe9b1866eb1ae8c9e2c4c4e567;p=mono.git diff --git a/mcs/mcs/convert.cs b/mcs/mcs/convert.cs index e442472283f..ed8e103cd77 100644 --- a/mcs/mcs/convert.cs +++ b/mcs/mcs/convert.cs @@ -10,12 +10,13 @@ // 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 @@ -23,8 +24,6 @@ namespace Mono.CSharp { static class Convert { static EmptyExpression MyEmptyExpr; - static DoubleHash explicit_conv; - static DoubleHash implicit_conv; static Convert () { @@ -34,209 +33,154 @@ namespace Mono.CSharp { public static void Reset () { MyEmptyExpr = null; - explicit_conv = new DoubleHash (100); - implicit_conv = new DoubleHash (100); } -#if GMCS_SOURCE - static Type TypeParam_EffectiveBaseType (GenericConstraints gc) - { - 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); - } -#endif - // // 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, bool isExplicit) + static bool ArrayToIList (ArrayContainer array, TypeSpec list, bool isExplicit) { -#if GMCS_SOURCE - if ((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 (element_type, arg_type); + 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 ImplicitReferenceConversionExists (MyEmptyExpr, arg_type); -#else - return false; -#endif } - 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) + public static Expression ImplicitTypeParameterConversion (Expression expr, TypeSpec target_type) { -#if GMCS_SOURCE - Type expr_type = expr.Type; + var expr_type = (TypeParameterSpec) 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; - GenericConstraints gc = TypeManager.GetTypeParameterConstraints (expr_type); + if (expr_type.IsReferenceType && !ttype.IsReferenceType) + return new BoxedCast (expr, target_type); - if (gc == null) { - if (target_type == TypeManager.object_type) - 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 because it's like T to object + // + 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 (it cannot contain dynamic of be of dynamic type) + // From T to any interface implemented by C + // + var base_type = expr_type.GetEffectiveBase (); + if (base_type == target_type || TypeSpec.IsBaseClass (base_type, target_type, false) || base_type.ImplementsInterface (target_type, true)) { + 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; + 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.IsSubclassOf (t, target_type)) - return true; - if (TypeManager.ImplementsInterface (t, target_type)) - return true; - } + return new BoxedCast (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; - } -#endif - - use_class_cast = false; - return false; + return null; } - static Expression ExplicitTypeParameterConversion (Expression source, 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 null; + 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; - foreach (Type iface in gc.InterfaceConstraints) { - if (!TypeManager.IsGenericParameter (iface)) - continue; + return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); + } + } +/* + if (target_tp.Interfaces != null) { + foreach (TypeSpec iface in target_tp.Interfaces) { + if (!TypeManager.IsGenericParameter (iface)) + continue; - if (TypeManager.IsSubclassOf (source_type, iface)) - return source == null ? EmptyExpression.Null : new ClassCast (source, target_type, true); + if (TypeManager.IsSubclassOf (source_type, iface)) + return source == null ? EmptyExpression.Null : new ClassCast (source, target_type, true); + } } +*/ + return null; } if (target_type.IsInterface) return source == null ? EmptyExpression.Null : new ClassCast (source, target_type, true); -#endif + return null; } - static Expression ImplicitReferenceConversion (Expression expr, Type target_type, bool explicit_cast) + public 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 @@ -247,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); // @@ -255,68 +199,69 @@ namespace Mono.CSharp { // NullLiteral nl = expr as NullLiteral; if (nl != null) { - return nl.ConvertImplicitly(target_type); + return nl.ConvertImplicitly (null, 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); } // // 6.1.6 Implicit reference conversions // - public static bool ImplicitReferenceConversionExists (Expression expr, Type target_type) + public static bool ImplicitReferenceConversionExists (Expression expr, TypeSpec target_type) { if (TypeManager.IsStruct (target_type)) return false; - Type expr_type = expr.Type; + TypeSpec expr_type = expr.Type; // from the null type to any reference-type. - if (expr_type == TypeManager.null_type) - return target_type != TypeManager.anonymous_method_type; + if (expr_type == InternalType.Null) + 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 // - // notice that it is possible to write "ValueType v = 1", the ValueType here - // is an abstract class, and not really a value type, so we apply the same rules. - // - if (target_type == TypeManager.object_type) { - // - // A pointer type cannot be converted to object - // - if (expr_type.IsPointer) - return false; + // Always ensure that the code here and there is in sync - 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; + // from any class-type S to any interface-type T. + if (target_type.IsInterface) { + if (expr_type.ImplementsInterface (target_type, true)){ + return !TypeManager.IsValueType (expr_type); } + } - return false; - } else if (target_type == TypeManager.value_type) { + // + // Implicit reference conversions (no-boxing) to object or dynamic + // + if (target_type == TypeManager.object_type || target_type == InternalType.Dynamic) { + switch (expr_type.Kind) { + case MemberKind.Class: + case MemberKind.Interface: + case MemberKind.Delegate: + case MemberKind.ArrayType: + return true; + } + + return expr_type == InternalType.Dynamic; + } + + if (target_type == TypeManager.value_type) { return expr_type == TypeManager.enum_type; - } else if (TypeManager.IsSubclassOf (expr_type, target_type)) { + } else if (expr_type == target_type || TypeSpec.IsBaseClass (expr_type, target_type, true)) { // // Special case: enumeration to System.Enum. // System.Enum is not a value type, it is a class, so we need @@ -324,42 +269,38 @@ 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; + + return true; } - if (expr_type.IsArray) { + 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.IsArray && expr_type.GetArrayRank () == target_type.GetArrayRank ()) { + if (target_type_array != null && expr_type_array.Rank == target_type_array.Rank) { // // Both SE and TE are reference-types // - Type expr_element_type = TypeManager.GetElementType (expr_type); + TypeSpec expr_element_type = expr_type_array.Element; if (!TypeManager.IsReferenceType (expr_element_type)) return false; - Type target_element_type = TypeManager.GetElementType (target_type); + TypeSpec target_element_type = target_type_array.Element; if (!TypeManager.IsReferenceType (target_element_type)) return false; if (MyEmptyExpr == null) - MyEmptyExpr = new EmptyExpression (); - - MyEmptyExpr.SetType (expr_element_type); + MyEmptyExpr = new EmptyExpression (expr_element_type); + else + MyEmptyExpr.SetType (expr_element_type); return ImplicitStandardConversionExists (MyEmptyExpr, target_element_type); } @@ -369,77 +310,93 @@ namespace Mono.CSharp { return true; // from an array-type of type T to IList - if (Array_To_IList (expr_type, target_type, false)) + if (ArrayToIList (expr_type_array, target_type, false)) return true; return false; } + if (TypeSpecComparer.IsEqual (expr_type, target_type)) + return true; + + if (TypeSpecComparer.Variant.IsEqual (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); + return expr_type.ImplementsInterface (target_type, true); } // 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; - if (TypeManager.IsEqual (expr_type, target_type)) - return true; - - if (TypeManager.IsVariantOf (expr_type, target_type)) - return true; - return false; } - public static 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; - return TypeManager.IsValueType (expr_type); + if (!TypeManager.IsValueType (expr_type)) + return null; + + 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 (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.IsEnumType (TypeManager.GetTypeArguments (expr_type) [0]); + return expr == null ? EmptyExpression.Null : new BoxedCast (expr, target_type); } - if (TypeManager.IsSubclassOf (expr_type, 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 (TypeSpec.IsBaseClass (expr_type, target_type, false)) { // // Don't box same type arguments // if (TypeManager.IsGenericParameter (expr_type) && expr_type != target_type) - return true; + return expr == null ? EmptyExpression.Null : new BoxedCast (expr, target_type); - return false; + return null; } // This code is kind of mirrored inside ImplicitStandardConversionExists @@ -449,55 +406,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, true) && + (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; } - static Expression ImplicitNulableConversion (EmitContext ec, Expression expr, Type target_type) + public static Expression ImplicitNulableConversion (ResolveContext ec, Expression expr, TypeSpec target_type) { - Type expr_type = expr.Type; + TypeSpec expr_type = expr.Type; // // From null to any nullable type // - if (expr_type == TypeManager.null_type) + if (expr_type == InternalType.Null) return ec == null ? EmptyExpression.Null : Nullable.LiftedNull.Create (target_type, expr.Location); - Type target = TypeManager.GetTypeArguments (target_type)[0]; - Expression e; + // S -> T? + TypeSpec t_el = Nullable.NullableInfo.GetUnderlyingType (target_type); // S? -> T? - if (TypeManager.IsNullableType (expr_type)) { - Type etype = TypeManager.GetTypeArguments (expr_type)[0]; + if (TypeManager.IsNullableType (expr_type)) + expr_type = Nullable.NullableInfo.GetUnderlyingType (expr_type); - if (ec == null) - return ImplicitConversionExists (ec, new EmptyExpression (etype), target) ? EmptyExpression.Null : null; + // + // Predefined implicit identity or implicit numeric conversion + // has to exist between underlying type S and underlying type T + // - Expression unwrap = Nullable.Unwrap.Create (expr); - e = ImplicitConversion (ec, unwrap, target, expr.Location); - if (e == null) - return null; + // conversion exists only mode + if (ec == null) { + if (TypeSpecComparer.IsEqual (expr_type, t_el)) + return EmptyExpression.Null; + + if (expr is Constant) + return ((Constant) expr).ConvertImplicitly (ec, t_el); - return new Nullable.Lifted (e, unwrap, target_type).Resolve (ec); + return ImplicitNumericConversion (null, expr_type, t_el); } - // S -> T? - if (ec == null) - return ImplicitConversionExists (ec, expr, target) ? EmptyExpression.Null : null; + Expression unwrap; + if (expr_type != expr.Type) + unwrap = Nullable.Unwrap.Create (expr); + else + unwrap = expr; - e = ImplicitConversion (ec, expr, target, expr.Location); - if (e != null) - return Nullable.Wrap.Create (e, target_type); + Expression conv = unwrap; + if (!TypeSpecComparer.IsEqual (expr_type, t_el)) { + if (conv is Constant) + conv = ((Constant)conv).ConvertImplicitly (ec, t_el); + else + conv = ImplicitNumericConversion (conv, expr_type, t_el); - return null; + 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); } /// @@ -506,12 +477,12 @@ 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. /// - public static Expression ImplicitNumericConversion (Expression expr, Type target_type) + public static Expression ImplicitNumericConversion (Expression expr, TypeSpec target_type) { return ImplicitNumericConversion (expr, expr.Type, target_type); } - static Expression ImplicitNumericConversion (Expression expr, Type expr_type, Type target_type) + static Expression ImplicitNumericConversion (Expression expr, TypeSpec expr_type, TypeSpec target_type) { if (expr_type == TypeManager.sbyte_type){ // @@ -601,9 +572,9 @@ namespace Mono.CSharp { 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); + return expr == null ? EmptyExpression.Null : new OpcodeCastDuplex (expr, target_type, OpCodes.Conv_R_Un, 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); + return expr == null ? EmptyExpression.Null : new OpcodeCastDuplex (expr, target_type, OpCodes.Conv_R_Un, OpCodes.Conv_R4); if (target_type == TypeManager.decimal_type) return expr == null ? EmptyExpression.Null : new CastToDecimal (expr); } else if (expr_type == TypeManager.int64_type){ @@ -621,9 +592,9 @@ namespace Mono.CSharp { // From ulong to float, double // 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); + return expr == null ? EmptyExpression.Null : new OpcodeCastDuplex (expr, target_type, OpCodes.Conv_R_Un, 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); + return expr == null ? EmptyExpression.Null : new OpcodeCastDuplex (expr, target_type, OpCodes.Conv_R_Un, OpCodes.Conv_R4); if (target_type == TypeManager.decimal_type) return expr == null ? EmptyExpression.Null : new CastToDecimal (expr); } else if (expr_type == TypeManager.char_type){ @@ -659,65 +630,74 @@ 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 (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; } /// /// Determines if a standard implicit conversion exists from /// expr_type to target_type /// - /// 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; + TypeSpec expr_type = expr.Type; - if (expr_type == TypeManager.null_type) { - NullLiteral nl = expr as NullLiteral; - if (nl != null) - return nl.ConvertImplicitly (target_type) != null; - } + NullLiteral nl = expr as NullLiteral; + if (nl != null) + return nl.ConvertImplicitly (null, target_type) != null; if (expr_type == TypeManager.void_type) return false; - 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; - } + if (expr_type == target_type) + return true; + + // Implicit dynamic conversion + if (expr_type == InternalType.Dynamic) { + switch (target_type.Kind) { + case MemberKind.ArrayType: + case MemberKind.Class: + case MemberKind.Struct: + case MemberKind.Delegate: + case MemberKind.Enum: + case MemberKind.Interface: + case MemberKind.TypeParameter: + return true; } + // dynamic to __arglist + if (target_type == InternalType.Arglist) + return true; + 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; - - if (TypeManager.IsNullableType (target_type)) + if (TypeManager.IsNullableType (target_type)) { return ImplicitNulableConversion (null, expr, target_type) != null; + } // First numeric conversions if (ImplicitNumericConversion (null, expr_type, target_type) != null) @@ -726,10 +706,9 @@ namespace Mono.CSharp { if (ImplicitReferenceConversionExists (expr, target_type)) return true; - bool use_class_cast; - if (ImplicitBoxingConversionExists (expr, target_type, out use_class_cast)) + if (ImplicitBoxingConversion (null, expr_type, target_type) != null) return true; - + // // Implicit Constant Expression Conversions // @@ -760,9 +739,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){ @@ -776,16 +752,35 @@ 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 && TypeManager.ImplementsInterface (expr_type, target_type)) + if (target_type.IsInterface && expr_type.ImplementsInterface (target_type, true)) 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; + + if (TypeSpecComparer.IsEqual (expr_type, target_type)) + return true; + return false; } @@ -793,19 +788,12 @@ 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) + public static TypeSpec FindMostEncompassedType (IEnumerable types) { - Type best = null; - - if (types.Count == 0) - return null; - - if (types.Count == 1) - return (Type) types [0]; - + TypeSpec best = null; EmptyExpression expr = EmptyExpression.Grab (); - foreach (Type t in types) { + foreach (TypeSpec t in types) { if (best == null) { best = t; continue; @@ -817,7 +805,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)) { @@ -835,19 +823,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; @@ -858,7 +846,7 @@ namespace Mono.CSharp { best = t; } - foreach (Type t in types) { + foreach (TypeSpec t in types) { if (best == t) continue; expr.SetType (t); @@ -873,37 +861,34 @@ namespace Mono.CSharp { return best; } - /// - /// Finds the most specific source Sx according to the rules of the spec (13.4.4) - /// by making use of FindMostEncomp* methods. Applies the correct rules separately - /// for explicit and implicit conversion operators. - /// - static public Type FindMostSpecificSource (IList list, - Expression source, bool apply_explicit_conv_rules) + // + // Finds the most specific source Sx according to the rules of the spec (13.4.4) + // by making use of FindMostEncomp* methods. Applies the correct rules separately + // for explicit and implicit conversion operators. + // + static TypeSpec FindMostSpecificSource (List list, TypeSpec sourceType, Expression source, bool apply_explicit_conv_rules) { - ArrayList src_types_set = new ArrayList (); + var src_types_set = new TypeSpec [list.Count]; // - // If any operator converts from S then Sx = S + // Try exact match first, if any operator converts from S then Sx = S // - Type source_type = source.Type; - foreach (MethodBase mb in list){ - AParametersCollection pd = TypeManager.GetParameterData (mb); - Type param_type = pd.Types [0]; + for (int i = 0; i < src_types_set.Length; ++i) { + TypeSpec param_type = list [i].Parameters.Types [0]; - if (param_type == source_type) + if (param_type == sourceType) return param_type; - src_types_set.Add (param_type); + src_types_set [i] = param_type; } // // 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); } @@ -924,16 +909,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; @@ -944,11 +929,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)) @@ -973,196 +958,247 @@ 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) { - AParametersCollection pd = TypeManager.GetParameterData (m); - Type return_type = TypeManager.TypeToCoreType (m.ReturnType); - Type arg_type = pd.Types [0]; + // Neither A nor B are interface-types + if (source.Type.IsInterface) + return; - 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; - } + // 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. + + Expression texpr = null; + + 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; } - if (target_type != return_type) { - expr.SetType (return_type); - if (!ImplicitStandardConversionExists (expr, target_type)) { - if (!look_for_explicit) + t = op.ReturnType; + + // LAMESPEC: Exclude UIntPtr -> int conversion + if (t == TypeManager.uint32_type && source.Type == TypeManager.uintptr_type) + continue; + + if (t.IsInterface) + continue; + + if (target != t) { + if (TypeManager.IsNullableType (t)) + t = Nullable.NullableInfo.GetUnderlyingType (t); + + if (!ImplicitStandardConversionExists (new EmptyExpression (t), target)) { + if (implicitOnly) continue; - expr.SetType (target_type); - if (!ImplicitStandardConversionExists (expr, return_type)) + + if (texpr == null) + texpr = new EmptyExpression (target); + + if (!ImplicitStandardConversionExists (texpr, t)) continue; } } - // See LAMESPEC: Exclude IntPtr -> int conversion - if (source_type == TypeManager.uintptr_type && return_type == TypeManager.uint32_type) - continue; + if (candidates == null) + candidates = new List (); - list.Add (m); + candidates.Add (op); } - - EmptyExpression.Release (expr); } - /// - /// 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, source_type and target_type are their underlying types + // otherwise source_type and target_type are equal to S and T respectively. + // + TypeSpec source_type = source.Type; + TypeSpec target_type = target; + Expression source_type_expr; - 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); - } + source_type_expr = Nullable.Unwrap.Create (source); + source_type = source_type_expr.Type; + } else { + source_type_expr = source; } - 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_type_expr, target_type, implicitOnly, ref candidates); + } - foreach (MethodInfo m in ops) { - if (TypeManager.TypeToCoreType (m.ReturnType) != most_specific_target) - continue; - if (TypeManager.GetParameterData (m).Types [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_type_expr, target_type, false, ref candidates); + } + } } - return method; - } + if ((target.Kind & user_conversion_kinds) != 0 && target_type != TypeManager.decimal_type) { + bool declared_only = target.IsStruct || implicitOnly; - /// - /// 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; + var operators = MemberCache.GetUserOperator (target_type, Operator.OpType.Implicit, declared_only); + if (operators != null) { + FindApplicableUserDefinedConversionOperators (operators, source_type_expr, target_type, implicitOnly, ref candidates); + } - object o; - DoubleHash hash; - if (look_for_explicit) { - hash = explicit_conv; + if (!implicitOnly) { + operators = MemberCache.GetUserOperator (target_type, Operator.OpType.Explicit, declared_only); + if (operators != null) { + FindApplicableUserDefinedConversionOperators (operators, source_type_expr, target_type, false, ref candidates); + } + } + } + + if (candidates == null) + return null; + + // + // 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 { - // Implicit user operators cannot convert to interfaces - if (target.IsInterface) + // + // Pass original source type to find the best match against input type and + // not the unwrapped expression + // + s_x = FindMostSpecificSource (candidates, source.Type, source_type_expr, !implicitOnly); + if (s_x == null) return null; - hash = implicit_conv; - } + t_x = FindMostSpecificTarget (candidates, target, !implicitOnly); + if (t_x == null) + return null; - 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); + most_specific_operator = null; + for (int i = 0; i < candidates.Count; ++i) { + if (candidates[i].ReturnType == t_x && candidates[i].Parameters.Types[0] == s_x) { + most_specific_operator = candidates[i]; + break; + } + } + + if (most_specific_operator == null) { + MethodSpec ambig_arg = null; + foreach (var candidate in candidates) { + if (candidate.ReturnType == t_x) + most_specific_operator = candidate; + else if (candidate.Parameters.Types[0] == s_x) + ambig_arg = candidate; + } + + ec.Report.Error (457, loc, + "Ambiguous user defined operators `{0}' and `{1}' when converting from `{2}' to `{3}'", + ambig_arg.GetSignatureForError (), most_specific_operator.GetSignatureForError (), + source.Type.GetSignatureForError (), target.GetSignatureForError ()); + } } - 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_type_expr, s_x, loc) : + ExplicitConversionStandard (ec, source_type_expr, s_x, loc); + else { + source = source_type_expr; + } - Type most_specific_source = TypeManager.GetParameterData (method).Types [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).DoResolve (ec); + if (source == null) + return null; + } + + // + // Source expression is of nullable type, lift the result in the case it's null and + // not nullable/lifted user operator is used + // + if (source_type_expr is Nullable.Unwrap && !TypeManager.IsNullableType (s_x) && (TypeManager.IsReferenceType (target) || target_type != target)) + source = new Nullable.Lifted (source, source_type_expr, target).Resolve (ec); + else if (target_type != target) + source = Nullable.Wrap.Create (source, target); + + return source; } /// @@ -1170,8 +1206,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; @@ -1200,13 +1236,13 @@ 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) { if (expr.eclass == ExprClass.MethodGroup){ if (!TypeManager.IsDelegateType (target_type)){ @@ -1224,17 +1260,39 @@ namespace Mono.CSharp { } } - Type expr_type = expr.Type; + TypeSpec expr_type = expr.Type; Expression e; - if (expr_type.Equals (target_type)) { - if (expr_type != TypeManager.null_type && expr_type != TypeManager.anonymous_method_type) + if (expr_type == target_type) { + if (expr_type != InternalType.Null && expr_type != InternalType.AnonymousMethod) return expr; return null; } - if (TypeManager.IsVariantOf (expr_type, target_type)) { - return expr; + if (expr_type == InternalType.Dynamic) { + switch (target_type.Kind) { + case MemberKind.ArrayType: + case MemberKind.Class: + if (target_type == TypeManager.object_type) + return EmptyCast.Create (expr, target_type); + + goto case MemberKind.Struct; + case MemberKind.Struct: + // TODO: Should really introduce MemberKind.Void + if (target_type == TypeManager.void_type) + return null; + + goto case MemberKind.Enum; + case MemberKind.Delegate: + case MemberKind.Enum: + case MemberKind.Interface: + case MemberKind.TypeParameter: + Arguments args = new Arguments (1); + args.Add (new Argument (expr)); + return new DynamicConversion (target_type, explicit_cast ? CSharpBinderFlags.ConvertExplicit : 0, args, loc).Resolve (ec); + } + + return null; } if (TypeManager.IsNullableType (target_type)) @@ -1246,7 +1304,7 @@ namespace Mono.CSharp { Constant c = expr as Constant; if (c != null) { try { - c = c.ConvertImplicitly (target_type); + c = c.ConvertImplicitly (ec, target_type); } catch { Console.WriteLine ("Conversion error happened in line {0}", loc); throw; @@ -1263,20 +1321,22 @@ namespace Mono.CSharp { if (e != null) return e; - if (expr is IntConstant && TypeManager.IsEnumType (target_type)){ - Constant i = (Constant) expr; + if (expr is IntegralConstant && TypeManager.IsEnumType (target_type)){ + var i = (IntegralConstant) expr; // - // LAMESPEC: Conversion from any 0 constant is allowed + // 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.IsDefaultValue) - return new EnumConstant (i, target_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); @@ -1293,17 +1353,23 @@ namespace Mono.CSharp { } } - if (expr_type == TypeManager.null_type && target_type.IsPointer) + if (expr_type == InternalType.Null && target_type.IsPointer) 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; + + if (TypeSpecComparer.IsEqual (expr_type, target_type)) + return expr; + return null; } @@ -1312,8 +1378,8 @@ 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) @@ -1344,10 +1410,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){ // @@ -1597,7 +1663,7 @@ 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) { Expression e = ExplicitReferenceConversion (null, source_type, target_type); if (e == null) @@ -1612,10 +1678,8 @@ namespace Mono.CSharp { /// /// Implements Explicit Reference conversions /// - static Expression ExplicitReferenceConversion (Expression source, Type source_type, Type target_type) + static Expression ExplicitReferenceConversion (Expression source, TypeSpec source_type, TypeSpec target_type) { - bool target_is_value_type = TypeManager.IsStruct (target_type); - // // From object to a generic parameter // @@ -1625,65 +1689,68 @@ namespace Mono.CSharp { // // Explicit type parameter conversion. // - if (TypeManager.IsGenericParameter (source_type)) + if (source_type.Kind == MemberKind.TypeParameter) return ExplicitTypeParameterConversion (source, source_type, target_type); - // - // From object to any reference type or value type (unboxing) - // - 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); + bool target_is_value_type = TypeManager.IsStruct (target_type) || TypeManager.IsEnumType (target_type); // - // Unboxing conversion from the types object and System.ValueType to any non-nullable-value-type + // Unboxing conversion from System.ValueType to any non-nullable-value-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 + // From object or dynamic to any reference type or value type (unboxing) // - if (TypeManager.IsSubclassOf (target_type, source_type)) - return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); + if (source_type == TypeManager.object_type || source_type == InternalType.Dynamic) { + if (target_type.IsPointer) + return null; + + 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 type S to any interface T, provides S is not sealed - // and provided S does not implement T. + // From any class S to any class-type T, provided S is a base class of T // - if (target_type.IsInterface && !source_type.IsSealed && - !TypeManager.ImplementsInterface (source_type, target_type)) { + if (source_type.Kind == MemberKind.Class && TypeSpec.IsBaseClass (target_type, source_type, true)) 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.IsClass) - return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); + if (!target_type.IsSealed || target_type.ImplementsInterface (source_type, true)) { + if (source == null) + return EmptyExpression.Null; // // 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); + return target_is_value_type ? new UnboxCast (source, target_type) : (Expression) new ClassCast (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)) + 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; } - if (source_type.IsArray) { - if (target_type.IsArray) { + 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 // @@ -1698,17 +1765,17 @@ namespace Mono.CSharp { // * 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_array.Rank == target_array.Rank) { - source_type = TypeManager.GetElementType (source_type); + source_type = source_array.Element; if (!TypeManager.IsReferenceType (source_type)) return null; - Type target_type_element = TypeManager.GetElementType (target_type); - if (!TypeManager.IsReferenceType (target_type_element)) + var target_element = target_array.Element; + if (!TypeManager.IsReferenceType (target_element)) return null; - if (ExplicitReferenceConversionExists (source_type, target_type_element)) + if (ExplicitReferenceConversionExists (source_type, target_element)) return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); return null; @@ -1719,18 +1786,66 @@ namespace Mono.CSharp { // 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)) + if (ArrayToIList (source_array, target_type, true)) return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); return null; } + // + // 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, true)) { + 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 source == null ? EmptyExpression.Null : new ClassCast (source, target_type); + // + // From variant generic delegate to same variant generic delegate type + // + if (source_type.IsDelegate && target_type.IsDelegate && source_type.MemberDefinition == target_type.MemberDefinition) { + var tparams = source_type.MemberDefinition.TypeParameters; + var targs_src = source_type.TypeArguments; + var targs_dst = target_type.TypeArguments; + int i; + for (i = 0; i < tparams.Length; ++i) { + // + // If TP is invariant, types have to be identical + // + if (TypeSpecComparer.IsEqual (targs_src[i], targs_dst[i])) + continue; + + if (tparams[i].Variance == Variance.Covariant) { + // + //If TP is covariant, an implicit or explicit identity or reference conversion is required + // + if (ImplicitReferenceConversionExists (new EmptyExpression (targs_src[i]), targs_dst[i])) + continue; + + if (ExplicitReferenceConversionExists (targs_src[i], targs_dst[i])) + continue; + + } else if (tparams[i].Variance == Variance.Contravariant) { + // + //If TP is contravariant, both are either identical or reference types + // + if (TypeManager.IsReferenceType (targs_src[i]) && TypeManager.IsReferenceType (targs_dst[i])) + continue; + } + + break; + } + + if (i == tparams.Length) + return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); + } + return null; } @@ -1738,10 +1853,10 @@ 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); @@ -1749,53 +1864,72 @@ namespace Mono.CSharp { return ne; 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); - return ExplicitUserConversion (ec, underlying, target_type, loc); + // + // 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 ne != null ? EmptyCast.Create (ne, target_type) : null; } - if (TypeManager.IsEnumType (target_type)){ + if (TypeManager.IsEnumType (target_type)) { // - // Type System.Enum can be unboxed to any enum-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); + 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){ + if (expr_type != InternalType.Null) { 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; @@ -1804,9 +1938,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) @@ -1819,25 +1953,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; @@ -1846,12 +1987,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) @@ -1865,7 +2006,7 @@ namespace Mono.CSharp { 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); @@ -1876,18 +2017,29 @@ 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 = ExplicitConversionCore (ec, expr, target_type, loc); - if (e != null) + 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; + } -#if GMCS_SOURCE - Type expr_type = expr.Type; + TypeSpec expr_type = expr.Type; if (TypeManager.IsNullableType (target_type)) { if (TypeManager.IsNullableType (expr_type)) { - Type target = TypeManager.GetTypeArguments (target_type)[0]; + TypeSpec target = Nullable.NullableInfo.GetUnderlyingType (target_type); Expression unwrap = Nullable.Unwrap.Create (expr); e = ExplicitConversion (ec, unwrap, target, expr.Location); if (e == null) @@ -1897,25 +2049,22 @@ namespace Mono.CSharp { } 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 = ExplicitUserConversion (ec, expr, target_type, loc); if (e != null)