2008-09-29 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mcs / mcs / convert.cs
index e54e14dd8ee35dcecc254edef093b3fcc063a997..931fe82665de4c930e87dc52bccbbcfcb7dc54ec 100644 (file)
@@ -52,18 +52,15 @@ namespace Mono.CSharp {
                }
 #endif
 
-               //
-               // From a one-dimensional array-type S[] to System.Collections.IList<S> and base
-               // interfaces of this interface.
                //
                // From a one-dimensional array-type S[] to System.Collections.IList<T> and base
                // interfaces of this interface, provided there is an implicit reference conversion
                // from S to T.
                //
-               static bool Array_To_IList (Type array, Type list)
+               static bool Array_To_IList (Type array, Type list, bool isExplicit)
                {
 #if GMCS_SOURCE
-                       if (!array.IsArray || (array.GetArrayRank () != 1) || !list.IsGenericType)
+                       if ((array.GetArrayRank () != 1) || !list.IsGenericType)
                                return false;
 
                        Type gt = list.GetGenericTypeDefinition ();
@@ -78,11 +75,14 @@ namespace Mono.CSharp {
                        if (element_type == arg_type)
                                return true;
 
+                       if (isExplicit)
+                               return ExplicitReferenceConversionExists (element_type, arg_type);
+
                        if (MyEmptyExpr == null)
                                MyEmptyExpr = new EmptyExpression ();
                        MyEmptyExpr.SetType (TypeManager.GetElementType (array));
 
-                       return ImplicitReferenceConversionCore (MyEmptyExpr, arg_type);
+                       return ImplicitReferenceConversionExists (MyEmptyExpr, arg_type);
 #else
                        return false;
 #endif
@@ -208,31 +208,9 @@ namespace Mono.CSharp {
                        return false;
                }
 
-               static bool ExplicitTypeParameterConversionExists (Type source_type, Type target_type)
+               static Expression ExplicitTypeParameterConversion (Expression source, Type source_type, Type target_type)
                {
 #if GMCS_SOURCE
-                       if (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;
-
-                                       if (TypeManager.IsSubclassOf (source_type, iface))
-                                               return true;
-                               }
-                       }
-#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)
@@ -243,12 +221,12 @@ namespace Mono.CSharp {
                                                continue;
 
                                        if (TypeManager.IsSubclassOf (source_type, iface))
-                                               return new ClassCast (source, target_type);
+                                               return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
                                }
                        }
 
                        if (target_type.IsInterface)
-                               return new ClassCast (source, target_type);
+                               return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
 #endif
                        return null;
                }
@@ -278,7 +256,7 @@ namespace Mono.CSharp {
                                return nl.ConvertImplicitly(target_type);
                        }
 
-                       if (ImplicitReferenceConversionCore (expr, target_type)) {
+                       if (ImplicitReferenceConversionExists (expr, target_type)) {
                                // 
                                // Reduce implicit reference conversion to object
                                //
@@ -299,10 +277,23 @@ namespace Mono.CSharp {
                        return null;
                }
 
-               static public bool ImplicitReferenceConversionCore (Expression expr, Type target_type)
+               //
+               // 6.1.6 Implicit reference conversions
+               //
+               public static bool ImplicitReferenceConversionExists (Expression expr, Type target_type)
                {
+                       if (target_type.IsValueType)
+                               return false;
+
                        Type expr_type = expr.Type;
 
+                       // from the null type to any reference-type.
+                       if (expr_type == TypeManager.null_type)
+                               return target_type != TypeManager.anonymous_method_type;
+
+                       if (TypeManager.IsGenericParameter (expr_type))
+                               return ImplicitTypeParameterConversion (expr, target_type) != null;
+
                        //
                        // notice that it is possible to write "ValueType v = 1", the ValueType here
                        // is an abstract class, and not really a value type, so we apply the same rules.
@@ -348,36 +339,44 @@ namespace Mono.CSharp {
                                }
                        }
 
-                       // from any interface type S to interface-type T.
-                       if (expr_type.IsInterface && target_type.IsInterface) {
-                               return TypeManager.ImplementsInterface (expr_type, target_type);
-                       }
-
-                       // from an array-type S to an array-type of type T
-                       if (expr_type.IsArray && target_type.IsArray) {
-                               if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
+                       if (expr_type.IsArray) {
+                               // from an array-type S to an array-type of type T
+                               if (target_type.IsArray && expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
 
+                                       //
+                                       // Both SE and TE are reference-types
+                                       //
                                        Type expr_element_type = TypeManager.GetElementType (expr_type);
+                                       if (!TypeManager.IsReferenceType (expr_element_type))
+                                               return false;
+
+                                       Type target_element_type = TypeManager.GetElementType (target_type);
+                                       if (!TypeManager.IsReferenceType (target_element_type))
+                                               return false;
 
                                        if (MyEmptyExpr == null)
                                                MyEmptyExpr = new EmptyExpression ();
 
                                        MyEmptyExpr.SetType (expr_element_type);
-                                       Type target_element_type = TypeManager.GetElementType (target_type);
 
-                                       if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
-                                               return ImplicitStandardConversionExists (
-                                                       MyEmptyExpr, target_element_type);
+                                       return ImplicitStandardConversionExists (MyEmptyExpr, target_element_type);
                                }
-                       }
 
-                       // from an array-type to System.Array
-                       if (expr_type.IsArray && target_type == TypeManager.array_type)
-                               return true;
+                               // from an array-type to System.Array
+                               if (target_type == TypeManager.array_type)
+                                       return true;
 
-                       // from an array-type of type T to IList<T>
-                       if (expr_type.IsArray && Array_To_IList (expr_type, target_type))
-                               return true;
+                               // from an array-type of type T to IList<T>
+                               if (Array_To_IList (expr_type, target_type, false))
+                                       return true;
+
+                               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);
+                       }
 
                        // from any delegate type to System.Delegate
                        if (target_type == TypeManager.delegate_type &&
@@ -428,9 +427,12 @@ namespace Mono.CSharp {
                                if (TypeManager.IsNullableType (expr_type))
                                        return TypeManager.GetTypeArguments (expr_type) [0].IsEnum;
                        }
-                       
+
                        if (TypeManager.IsSubclassOf (expr_type, target_type)) {
-                               if (TypeManager.IsGenericParameter (expr_type))
+                               //
+                               // Don't box same type arguments
+                               //
+                               if (TypeManager.IsGenericParameter (expr_type) && expr_type != target_type)
                                        return true;
 
                                return false;
@@ -455,33 +457,6 @@ namespace Mono.CSharp {
                        return false;
                }
 
-               //
-               // Tests whether an implicit reference conversion exists between expr_type
-               // and target_type
-               //
-               public static bool ImplicitReferenceConversionExists (Expression expr, Type target_type)
-               {
-                       if (target_type.IsValueType)
-                               return false;
-
-                       Type expr_type = expr.Type;
-
-                       // from the null type to any reference-type.
-                       if (expr_type == TypeManager.null_type){
-                               return target_type != TypeManager.anonymous_method_type;
-                       }
-
-                       if (TypeManager.IsGenericParameter (expr_type))
-                               return ImplicitTypeParameterConversion (expr, target_type) != null;
-
-                       bool use_class_cast;
-                       if (ImplicitReferenceConversionCore (expr, target_type) ||
-                           ImplicitBoxingConversionExists (expr, target_type, out use_class_cast))
-                               return true;
-
-                       return false;
-               }
-
                /// <summary>
                ///   Implicit Numeric Conversions.
                ///
@@ -698,6 +673,17 @@ namespace Mono.CSharp {
                        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;
+                                       }
+                               }
+
+                               return false;
+                       }
+
                        //Console.WriteLine ("Expr is {0}", expr);
                        //Console.WriteLine ("{0} -> {1} ?", expr_type, target_type);
                        if (TypeManager.IsEqual (expr_type, target_type))
@@ -810,20 +796,13 @@ namespace Mono.CSharp {
                                        return true;
                        }
 
-                       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;
-                       }
-
                        if (ImplicitReferenceConversionExists (expr, target_type))
                                return true;
 
+                       bool use_class_cast;
+                       if (ImplicitBoxingConversionExists (expr, target_type, out use_class_cast))
+                               return true;
+
                        //
                        // Implicit Constant Expression Conversions
                        //
@@ -982,8 +961,8 @@ namespace Mono.CSharp {
                        //
                        Type source_type = source.Type;
                        foreach (MethodBase mb in list){
-                               ParameterData pd = TypeManager.GetParameterData (mb);
-                               Type param_type = pd.ParameterType (0);
+                               AParametersCollection pd = TypeManager.GetParameterData (mb);
+                               Type param_type = pd.Types [0];
 
                                if (param_type == source_type)
                                        return param_type;
@@ -1115,9 +1094,9 @@ namespace Mono.CSharp {
                        }
 
                        foreach (MethodInfo m in mg.Methods) {
-                               ParameterData pd = TypeManager.GetParameterData (m);
+                               AParametersCollection pd = TypeManager.GetParameterData (m);
                                Type return_type = TypeManager.TypeToCoreType (m.ReturnType);
-                               Type arg_type = pd.ParameterType (0);
+                               Type arg_type = pd.Types [0];
 
                                if (source_type != arg_type) {
                                        if (!ImplicitStandardConversionExists (source, arg_type)) {
@@ -1196,7 +1175,7 @@ namespace Mono.CSharp {
                        foreach (MethodInfo m in ops) {
                                if (TypeManager.TypeToCoreType (m.ReturnType) != most_specific_target)
                                        continue;
-                               if (TypeManager.GetParameterData (m).ParameterType (0) != most_specific_source)
+                               if (TypeManager.GetParameterData (m).Types [0] != most_specific_source)
                                        continue;
                                // Ambiguous: more than one conversion operator satisfies the signature.
                                if (method != null)
@@ -1221,7 +1200,16 @@ namespace Mono.CSharp {
                        MethodInfo method = null;
 
                        object o;
-                       DoubleHash hash = look_for_explicit ? explicit_conv : implicit_conv;
+                       DoubleHash hash;
+                       if (look_for_explicit) {
+                               hash = explicit_conv;
+                       } else {
+                               // Implicit user operators cannot convert to interfaces
+                               if (target.IsInterface)
+                                       return null;
+
+                               hash = implicit_conv;
+                       }                       
 
                        if (!(source is Constant) && hash.Lookup (source_type, target, out o)) {
                                method = (MethodInfo) o;
@@ -1234,7 +1222,7 @@ namespace Mono.CSharp {
                        if (method == null)
                                return null;
 
-                       Type most_specific_source = TypeManager.GetParameterData (method).ParameterType (0);
+                       Type most_specific_source = TypeManager.GetParameterData (method).Types [0];
 
                        //
                        // This will do the conversion to the best match that we
@@ -1250,7 +1238,7 @@ namespace Mono.CSharp {
                        if (source == null)
                                return null;
 
-                       return new UserCast (method, source, loc);
+                       return new UserCast (method, source, loc).DoResolve (ec);
                }
 
                /// <summary>
@@ -1339,8 +1327,11 @@ namespace Mono.CSharp {
                                }
                        }
 
-                       if (expr_type.Equals (target_type) && expr_type != TypeManager.null_type)
-                               return expr;
+                       if (expr_type.Equals (target_type)) {
+                               if (expr_type != TypeManager.null_type && expr_type != TypeManager.anonymous_method_type)
+                                       return expr;
+                               return null;
+                       }
 
                        //
                        // Attempt to do the implicit constant expression conversions
@@ -1372,11 +1363,17 @@ 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 IntConstant && TypeManager.IsEnumType (target_type)){
+                               Constant i = (Constant) expr;
+                               //
+                               // LAMESPEC: Conversion from any 0 constant is allowed
+                               //
+                               // An implicit enumeration conversion permits the decimal-integer-literal 0
+                               // to be converted to any enum-type and to any nullable-type whose underlying
+                               // type is an enum-type
+                               //
+                               if (i.IsDefaultValue)
+                                       return new EnumConstant (i, target_type);
                        }
 
                        if (ec.InUnsafe) {
@@ -1397,7 +1394,7 @@ 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){
@@ -1702,129 +1699,40 @@ namespace Mono.CSharp {
                /// </summary>
                public static bool ExplicitReferenceConversionExists (Type source_type, Type target_type)
                {
-                       bool target_is_type_param = TypeManager.IsGenericParameter (target_type);
-                       bool target_is_value_type = target_type.IsValueType;
-
-                       if (source_type == target_type)
-                               return true;
-
-                       //
-                       // From generic parameter to any type
-                       //
-                       if (TypeManager.IsGenericParameter (source_type))
-                               return ExplicitTypeParameterConversionExists (source_type, target_type);
-
-                       //
-                       // From object to a generic parameter
-                       //
-                       if (source_type == TypeManager.object_type && target_is_type_param)
-                               return true;
-
-                       //
-                       // From object to any reference type
-                       //
-                       if (source_type == TypeManager.object_type && !target_is_value_type)
-                               return true;
-
-                       //
-                       // From any class S to any class-type T, provided S is a base class of T
-                       //
-                       if (TypeManager.IsSubclassOf (target_type, source_type))
-                               return true;
-
-                       //
-                       // From any interface type S to any interface T provided S is not derived from T
-                       //
-                       if (source_type.IsInterface && target_type.IsInterface){
-                               if (!TypeManager.IsSubclassOf (target_type, source_type))
-                                       return true;
-                       }
-
-                       //
-                       // From any class type S to any interface T, provided S is not sealed
-                       // and provided S does not implement T.
-                       //
-                       if (target_type.IsInterface && !source_type.IsSealed &&
-                           !TypeManager.ImplementsInterface (source_type, target_type))
-                               return true;
-
-                       //
-                       // From any interface-type S to to any class type T, provided T is not
-                       // sealed, or provided T implements S.
-                       //
-                       if (source_type.IsInterface &&
-                           (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)))
-                               return true;
-
-
-                       if (source_type.IsInterface && IList_To_Array (source_type, target_type))
-                               return true;
-
-                       // From an array type S with an element type Se to an array type T with an
-                       // element type Te provided all the following are true:
-                       //     * S and T differe only in element type, in other words, S and T
-                       //       have the same number of dimensions.
-                       //     * Both Se and Te are reference types
-                       //     * An explicit referenc conversions exist from Se to Te
-                       //
-                       if (source_type.IsArray && target_type.IsArray) {
-                               if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
-
-                                       Type source_element_type = TypeManager.GetElementType (source_type);
-                                       Type target_element_type = TypeManager.GetElementType (target_type);
-
-                                       if (TypeManager.IsGenericParameter (source_element_type) ||
-                                           (!source_element_type.IsValueType && !target_element_type.IsValueType))
-                                               if (ExplicitReferenceConversionExists (source_element_type,
-                                                                                      target_element_type))
-                                                       return true;
-                               }
-                       }
-
-
-                       // From System.Array to any array-type
-                       if (source_type == TypeManager.array_type &&
-                           target_type.IsArray){
-                               return true;
-                       }
+                       Expression e = ExplicitReferenceConversion (null, source_type, target_type);
+                       if (e == null)
+                               return false;
 
-                       //
-                       // From System delegate to any delegate-type
-                       //
-                       if (source_type == TypeManager.delegate_type &&
-                           TypeManager.IsDelegateType (target_type))
+                       if (e == EmptyExpression.Null)
                                return true;
 
-                       return false;
+                       throw new InternalErrorException ("Invalid probing conversion result");
                }
 
                /// <summary>
                ///   Implements Explicit Reference conversions
                /// </summary>
-               static Expression ExplicitReferenceConversion (Expression source, Type target_type)
+               static Expression ExplicitReferenceConversion (Expression source, Type source_type, Type target_type)
                {
-                       Type source_type = source.Type;
-                       bool target_is_type_param = TypeManager.IsGenericParameter (target_type);
                        bool target_is_value_type = target_type.IsValueType;
 
                        //
                        // From object to a generic parameter
                        //
-                       if (source_type == TypeManager.object_type && target_is_type_param)
-                               return new UnboxCast (source, target_type);
+                       if (source_type == TypeManager.object_type && TypeManager.IsGenericParameter (target_type))
+                               return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type);
 
                        //
                        // Explicit type parameter conversion.
                        //
-
                        if (TypeManager.IsGenericParameter (source_type))
-                               return ExplicitTypeParameterConversion (source, target_type);
+                               return ExplicitTypeParameterConversion (source, source_type, target_type);
 
                        //
                        // From object to any reference type
                        //
                        if (source_type == TypeManager.object_type && !target_is_value_type)
-                               return new ClassCast (source, target_type);
+                               return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
 
                        //
                        // Unboxing conversion.
@@ -1832,32 +1740,21 @@ namespace Mono.CSharp {
                        if (((source_type == TypeManager.enum_type &&
                                !(source is TypeCast)) ||
                                source_type == TypeManager.value_type) && target_is_value_type)
-                               return new UnboxCast (source, target_type);
+                               return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type);
 
                        //
                        // From any class S to any class-type T, provided S is a base class of T
                        //
                        if (TypeManager.IsSubclassOf (target_type, source_type))
-                               return new ClassCast (source, target_type);
-
-                       //
-                       // From any interface type S to any interface T provided S is not derived from T
-                       //
-                       if (source_type.IsInterface && target_type.IsInterface){
-                               if (TypeManager.ImplementsInterface (source_type, target_type))
-                                       return null;
-                               else
-                                       return new ClassCast (source, target_type);
-                       }
+                               return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
 
                        //
                        // From any class type S to any interface T, provides S is not sealed
                        // and provided S does not implement T.
                        //
-                       if (target_type.IsInterface &&
-                               (!source_type.IsSealed || source_type.IsArray) &&       // SRE: IsSealed does not work with aggregates
+                       if (target_type.IsInterface && !source_type.IsSealed &&
                                !TypeManager.ImplementsInterface (source_type, target_type)) {
-                               return new ClassCast (source, target_type);
+                               return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
                        }
 
                        //
@@ -1867,9 +1764,9 @@ namespace Mono.CSharp {
                        if (source_type.IsInterface) {
                                if (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)) {
                                        if (target_type.IsClass)
-                                               return new ClassCast (source, target_type);
-                                       else
-                                               return new UnboxCast (source, target_type);
+                                               return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
+
+                                       return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type);
                                }
 
                                //
@@ -1877,44 +1774,59 @@ namespace Mono.CSharp {
                                // array type S[], provided there is an implicit or explicit reference conversion from S to T.
                                //
                                if (IList_To_Array (source_type, target_type))
-                                       return new ClassCast (source, target_type);
+                                       return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
 
                                return null;
                        }
 
-                       // From an array type S with an element type Se to an array type T with an
-                       // element type Te provided all the following are true:
-                       //     * S and T differe only in element type, in other words, S and T
-                       //       have the same number of dimensions.
-                       //     * Both Se and Te are reference types
-                       //     * An explicit referenc conversions exist from Se to Te
-                       //
-                       if (source_type.IsArray && target_type.IsArray) {
-                               if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
+                       if (source_type.IsArray) {
+                               if (target_type.IsArray) {
+                                       //
+                                       // From System.Array to any array-type
+                                       //
+                                       if (source_type == TypeManager.array_type)
+                                               return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
 
-                                       Type source_element_type = TypeManager.GetElementType (source_type);
-                                       Type target_element_type = TypeManager.GetElementType (target_type);
+                                       //
+                                       // From an array type S with an element type Se to an array type T with an
+                                       // element type Te provided all the following are true:
+                                       //     * S and T differe only in element type, in other words, S and T
+                                       //       have the same number of dimensions.
+                                       //     * Both Se and Te are reference types
+                                       //     * An explicit reference conversions exist from Se to Te
+                                       //
+                                       if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
+
+                                               source_type = TypeManager.GetElementType (source_type);
+                                               if (!TypeManager.IsReferenceType (source_type))
+                                                       return null;
+
+                                               Type target_type_element = TypeManager.GetElementType (target_type);
+                                               if (!TypeManager.IsReferenceType (target_type_element))
+                                                       return null;
 
-                                       if (!source_element_type.IsValueType && !target_element_type.IsValueType)
-                                               if (ExplicitReferenceConversionExists (source_element_type,
-                                                                                      target_element_type))
-                                                       return new ClassCast (source, target_type);
+                                               if (ExplicitReferenceConversionExists (source_type, target_type_element))
+                                                       return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
+                                                       
+                                               return null;
+                                       }
                                }
-                       }
 
+                               //
+                               // From a single-dimensional array type S[] to System.Collections.Generic.IList<T> and its base interfaces, 
+                               // provided that there is an explicit reference conversion from S to T
+                               //
+                               if (Array_To_IList (source_type, target_type, true))
+                                       return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
 
-                       // From System.Array to any array-type
-                       if (source_type == TypeManager.array_type &&
-                           target_type.IsArray) {
-                               return new ClassCast (source, target_type);
+                               return null;
                        }
 
                        //
                        // From System delegate to any delegate-type
                        //
-                       if (source_type == TypeManager.delegate_type &&
-                           TypeManager.IsDelegateType (target_type))
-                               return new ClassCast (source, target_type);
+                       if (source_type == TypeManager.delegate_type && TypeManager.IsDelegateType (target_type))
+                               return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
 
                        return null;
                }
@@ -1959,11 +1871,11 @@ namespace Mono.CSharp {
                                //
                                // LAMESPEC: IntPtr and UIntPtr conversion to any Enum is allowed
                                //
-                if (expr_type == TypeManager.intptr_type || expr_type == TypeManager.uintptr_type) {
+                               if (expr_type == TypeManager.intptr_type || expr_type == TypeManager.uintptr_type) {
                                        ne = ExplicitUserConversion (ec, expr, TypeManager.GetEnumUnderlyingType (target_type), loc);
                                        if (ne != null)
                                                return ExplicitConversionCore (ec, ne, target_type, loc);
-                }
+                               }
                                
                                return null;
                        }
@@ -1978,7 +1890,7 @@ namespace Mono.CSharp {
                        // null literal explicitly
                        //
                        if (expr_type != TypeManager.null_type){
-                               ne = ExplicitReferenceConversion (expr, target_type);
+                               ne = ExplicitReferenceConversion (expr, expr_type, target_type);
                                if (ne != null)
                                        return ne;
                        }
@@ -2049,7 +1961,7 @@ 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;