X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fconvert.cs;h=5a1ebe831644b3503fed44d4b0f3eacdf4a1a14e;hb=21dd2b0200d091c43fce9e1941e8ab5e111f3651;hp=533f828c4ff0711e234d29a9ec36e87322642295;hpb=9c05ae86ad8ca9ac33546be6d616828d75af4372;p=mono.git diff --git a/mcs/mcs/convert.cs b/mcs/mcs/convert.cs index 533f828c4ff..5a1ebe83164 100644 --- a/mcs/mcs/convert.cs +++ b/mcs/mcs/convert.cs @@ -24,8 +24,6 @@ namespace Mono.CSharp { static class Convert { static EmptyExpression MyEmptyExpr; - static DoubleHash explicit_conv; - static DoubleHash implicit_conv; static Convert () { @@ -35,188 +33,143 @@ namespace Mono.CSharp { public static void Reset () { MyEmptyExpr = null; - explicit_conv = new DoubleHash (100); - implicit_conv = new DoubleHash (100); } - static Type TypeParam_EffectiveBaseType (GenericConstraints gc) - { - var list = new List (); - 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); - } - // // 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 ((array.GetArrayRank () != 1) || !TypeManager.IsGenericType (list)) + if (array.Rank != 1 || !list.IsGeneric) return false; - Type gt = TypeManager.DropGenericTypeArguments (list); - 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.TypeToCoreType (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); - Type t = TypeManager.GetElementType (array); if (MyEmptyExpr == null) - MyEmptyExpr = new EmptyExpression (t); + MyEmptyExpr = new EmptyExpression (array.Element); else - MyEmptyExpr.SetType (t); + MyEmptyExpr.SetType (array.Element); return ImplicitReferenceConversionExists (MyEmptyExpr, arg_type); } - static bool IList_To_Array(Type list, Type array) + static bool IList_To_Array(TypeSpec list, ArrayContainer array) { - if (!TypeManager.IsGenericType (list) || !array.IsArray || array.GetArrayRank() != 1) + if (array.Rank != 1 || !list.IsGeneric) return false; - - Type gt = TypeManager.DropGenericTypeArguments (list); - 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.TypeToCoreType (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(element_type); + MyEmptyExpr = new EmptyExpression (array.Element); else - MyEmptyExpr.SetType(element_type); - - return ImplicitReferenceConversionExists(MyEmptyExpr, arg_type) || ExplicitReferenceConversionExists(element_type, arg_type); + MyEmptyExpr.SetType (array.Element); + + return ImplicitReferenceConversionExists (MyEmptyExpr, arg_type) || ExplicitReferenceConversionExists (array.Element, arg_type); } - static Expression ImplicitTypeParameterConversion (Expression expr, - Type target_type) + static Expression ImplicitTypeParameterConversion (Expression expr, TypeSpec target_type) { - 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); + // + // LAMESPEC: From T to dynamic type + // + if (target_type == InternalType.Dynamic) { + if (expr_type.IsReferenceType) + return new ClassCast (expr, target_type); - if (TypeManager.IsSubclassOf (base_type, target_type)) - return new ClassCast (expr, target_type); + return new BoxedCast (expr, target_type); + } - if (target_type.IsInterface) { - if (TypeManager.ImplementsInterface (base_type, target_type)) + // + // From T to its effective base class C + // From T to any base class of C + // From T to any interface implemented by C + // + var base_type = expr_type.GetEffectiveBase (); + if (base_type == target_type || TypeManager.IsSubclassOf (base_type, target_type) || base_type.ImplementsInterface (target_type)) { + if (expr_type.IsReferenceType) return new ClassCast (expr, target_type); - 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)) + if (target_type.IsInterface && expr_type.IsConvertibleToInterface (target_type)) { + if (expr_type.IsReferenceType) return new ClassCast (expr, target_type); + + return new BoxedCast (expr, target_type); } return null; } - static bool ImplicitTypeParameterBoxingConversion (Type expr_type, Type target_type, - out bool use_class_cast) + static Expression ExplicitTypeParameterConversion (Expression source, TypeSpec source_type, TypeSpec target_type) { - GenericConstraints gc = TypeManager.GetTypeParameterConstraints (expr_type); - - if (gc == null) { - use_class_cast = false; - return target_type == TypeManager.object_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; + 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 t in gc.InterfaceConstraints) { - if (TypeManager.IsSubclassOf (t, target_type)) - return true; - if (TypeManager.ImplementsInterface (t, target_type)) - return true; + return source == null ? EmptyExpression.Null : new ClassCast (source, 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; - } - - use_class_cast = false; - return false; - } - static Expression ExplicitTypeParameterConversion (Expression source, Type source_type, Type target_type) - { - if (TypeManager.IsGenericParameter (target_type)) { - GenericConstraints gc = TypeManager.GetTypeParameterConstraints (target_type); - if (gc == null) - return null; - - foreach (Type iface in gc.InterfaceConstraints) { - if (!TypeManager.IsGenericParameter (iface)) - continue; + if (target_tp.Interfaces != null) { + foreach (TypeSpec iface in target_tp.Interfaces) { + if (!TypeManager.IsGenericParameter (iface)) + continue; - if (TypeManager.IsSubclassOf (source_type, iface)) - return 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) @@ -225,9 +178,9 @@ namespace Mono.CSharp { return null; } - static Expression ImplicitReferenceConversion (Expression expr, Type target_type, bool explicit_cast) + static Expression ImplicitReferenceConversion (Expression expr, TypeSpec target_type, bool explicit_cast) { - Type expr_type = expr.Type; + TypeSpec expr_type = expr.Type; if (expr_type == null && expr.eclass == ExprClass.MethodGroup){ // if we are a method group, emit a warning @@ -238,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); // @@ -259,26 +212,18 @@ namespace Mono.CSharp { 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) @@ -287,11 +232,23 @@ namespace Mono.CSharp { if (TypeManager.IsGenericParameter (expr_type)) return ImplicitTypeParameterConversion (expr, target_type) != null; + // This code is kind of mirrored inside ImplicitStandardConversionExists + // with the small distinction that we only probe there + // + // Always ensure that the code here and there is in sync + + // from any class-type S to any interface-type T. + if (target_type.IsInterface) { + if (expr_type.ImplementsInterface (target_type)){ + return !TypeManager.IsValueType (expr_type); + } + } + // // notice that it is possible to write "ValueType v = 1", the ValueType here // is an abstract class, and not really a value type, so we apply the same rules. // - if (target_type == TypeManager.object_type || TypeManager.IsDynamicType (target_type)) { + if (target_type == TypeManager.object_type || target_type == InternalType.Dynamic) { // // A pointer type cannot be converted to object // @@ -301,11 +258,19 @@ namespace Mono.CSharp { if (TypeManager.IsValueType (expr_type)) return false; - if (expr_type.IsClass || expr_type.IsInterface || expr_type == TypeManager.enum_type){ + if (expr_type.IsClass || expr_type.IsInterface || expr_type == TypeManager.enum_type || expr_type.IsDelegate || expr_type.Kind == MemberKind.ArrayType) { // No mcs internal types are convertible - return expr_type.Module != typeof (Convert).Module; + return true; // expr_type.MetaInfo.Module != typeof (Convert).Module; } + // From anything to dynamic + if (target_type == InternalType.Dynamic) + return true; + + // From dynamic to object + if (expr_type == InternalType.Dynamic) + return true; + return false; } else if (target_type == TypeManager.value_type) { return expr_type == TypeManager.enum_type; @@ -317,35 +282,31 @@ 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; @@ -362,23 +323,23 @@ 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 (TypeManager.IsVariantOf (expr_type, target_type)) + 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); } // 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)) @@ -387,42 +348,58 @@ namespace Mono.CSharp { 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 || TypeManager.IsDynamicType (target_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); + } + + // + // From a nullable-type to a reference type, if a boxing conversion exists from + // the underlying type to the reference type + // + if (TypeManager.IsNullableType (expr_type)) { + if (!TypeManager.IsReferenceType (target_type)) + return null; + + var res = ImplicitBoxingConversion (expr, Nullable.NullableInfo.GetUnderlyingType (expr_type), target_type); + + // "cast" underlying type to target type to emit correct InvalidCastException when + // underlying hierarchy changes without recompilation + if (res != null && expr != null) + res = new UnboxCast (res, target_type); + + return res; } if (TypeManager.IsSubclassOf (expr_type, target_type)) { @@ -430,9 +407,9 @@ namespace Mono.CSharp { // 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 @@ -442,21 +419,18 @@ namespace Mono.CSharp { // from any class-type S to any interface-type T. if (target_type.IsInterface) { - if (TypeManager.ImplementsInterface (expr_type, target_type)) - return TypeManager.IsGenericParameter (expr_type) || - TypeManager.IsValueType (expr_type); + if (expr_type.ImplementsInterface (target_type) && + (TypeManager.IsGenericParameter (expr_type) || TypeManager.IsValueType (expr_type))) { + return expr == null ? EmptyExpression.Null : new BoxedCast (expr, target_type); + } } - if (TypeManager.IsGenericParameter (expr_type)) - return ImplicitTypeParameterBoxingConversion ( - expr_type, target_type, out use_class_cast); - - return false; + return null; } - public static Expression ImplicitNulableConversion (ResolveContext 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 @@ -465,22 +439,25 @@ namespace Mono.CSharp { return ec == null ? EmptyExpression.Null : Nullable.LiftedNull.Create (target_type, expr.Location); // S -> T? - Type t_el = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (target_type)[0]); + TypeSpec t_el = Nullable.NullableInfo.GetUnderlyingType (target_type); // S? -> T? if (TypeManager.IsNullableType (expr_type)) - expr_type = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (expr_type)[0]); + expr_type = Nullable.NullableInfo.GetUnderlyingType (expr_type); // // Predefined implicit identity or implicit numeric conversion // has to exist between underlying type S and underlying type T // - // Handles probing + // conversion exists only mode if (ec == null) { if (expr_type == t_el) return EmptyExpression.Null; + if (expr is Constant) + return ((Constant) expr).ConvertImplicitly (ec, t_el); + return ImplicitNumericConversion (null, expr_type, t_el); } @@ -490,17 +467,20 @@ namespace Mono.CSharp { else unwrap = expr; - Expression conv = expr_type == t_el ? unwrap : ImplicitNumericConversion (unwrap, expr_type, t_el); - if (conv == null) - return null; + Expression conv = unwrap; + if (expr_type != t_el) { + if (conv is Constant) + conv = ((Constant)conv).ConvertImplicitly (ec, t_el); + else + conv = ImplicitNumericConversion (conv, expr_type, t_el); + if (conv == null) + return null; + } + if (expr_type != expr.Type) return new Nullable.Lifted (conv, unwrap, target_type).Resolve (ec); - // Do constant optimization for S -> T? - if (unwrap is Constant) - conv = ((Constant) unwrap).ConvertImplicitly (ec, t_el); - return Nullable.Wrap.Create (conv, target_type); } @@ -510,12 +490,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){ // @@ -663,14 +643,13 @@ namespace Mono.CSharp { /// Same as ImplicitStandardConversionExists except that it also looks at /// implicit user defined conversions - needed for overload resolution /// - public static bool ImplicitConversionExists (ResolveContext 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 == InternalType.AnonymousMethod) { - if (!TypeManager.IsDelegateType (target_type) && - TypeManager.DropGenericTypeArguments (target_type) != TypeManager.expression_type) + if (!TypeManager.IsDelegateType (target_type) && target_type.GetDefinition () != TypeManager.expression_type) return false; AnonymousMethodExpression ame = (AnonymousMethodExpression) expr; @@ -678,7 +657,7 @@ namespace Mono.CSharp { } if (expr.eclass == ExprClass.MethodGroup) { - if (TypeManager.IsDelegateType (target_type) && RootContext.Version != LanguageVersion.ISO_1) { + if (target_type.IsDelegate && RootContext.Version != LanguageVersion.ISO_1) { MethodGroupExpr mg = expr as MethodGroupExpr; if (mg != null) return DelegateCreation.ImplicitStandardConversionExists (ec, mg, target_type); @@ -696,9 +675,9 @@ namespace Mono.CSharp { /// /// ec should point to a real EmitContext if expr.Type is TypeManager.anonymous_method_type. /// - public static bool ImplicitStandardConversionExists (Expression expr, Type target_type) + public static bool ImplicitStandardConversionExists (Expression expr, TypeSpec target_type) { - Type expr_type = expr.Type; + TypeSpec expr_type = expr.Type; if (expr_type == TypeManager.null_type) { NullLiteral nl = expr as NullLiteral; @@ -723,8 +702,7 @@ 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; // @@ -757,9 +735,6 @@ namespace Mono.CSharp { if (value >= 0) return true; } - - if (value == 0 && TypeManager.IsEnumType (target_type)) - return true; } if (expr is LongConstant && target_type == TypeManager.uint64_type){ @@ -773,11 +748,23 @@ 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)) return true; if (target_type == TypeManager.void_ptr_type && expr_type.IsPointer) @@ -794,19 +781,12 @@ namespace Mono.CSharp { /// Finds "most encompassed type" according to the spec (13.4.2) /// amongst the methods in the MethodGroupExpr /// - static Type FindMostEncompassedType (IList 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; @@ -818,7 +798,7 @@ namespace Mono.CSharp { } expr.SetType (best); - foreach (Type t in types) { + foreach (TypeSpec t in types) { if (best == t) continue; if (!ImplicitStandardConversionExists (expr, t)) { @@ -836,9 +816,9 @@ namespace Mono.CSharp { /// Finds "most encompassing type" according to the spec (13.4.2) /// amongst the types in the given set /// - static Type FindMostEncompassingType (IList types) + static TypeSpec FindMostEncompassingType (IList types) { - Type best = null; + TypeSpec best = null; if (types.Count == 0) return null; @@ -848,7 +828,7 @@ namespace Mono.CSharp { EmptyExpression expr = EmptyExpression.Grab (); - foreach (Type t in types) { + foreach (TypeSpec t in types) { if (best == null) { best = t; continue; @@ -859,7 +839,7 @@ namespace Mono.CSharp { best = t; } - foreach (Type t in types) { + foreach (TypeSpec t in types) { if (best == t) continue; expr.SetType (t); @@ -879,17 +859,17 @@ namespace Mono.CSharp { /// by making use of FindMostEncomp* methods. Applies the correct rules separately /// for explicit and implicit conversion operators. /// - static public Type FindMostSpecificSource (IList list, + static TypeSpec FindMostSpecificSource (IList list, Expression source, bool apply_explicit_conv_rules) { - var src_types_set = new List (); + var src_types_set = new List (); // // If any operator converts from S then Sx = S // - Type source_type = source.Type; + TypeSpec source_type = source.Type; foreach (var mb in list){ - Type param_type = mb.Parameters.Types [0]; + TypeSpec param_type = mb.Parameters.Types [0]; if (param_type == source_type) return param_type; @@ -901,9 +881,9 @@ namespace Mono.CSharp { // Explicit Conv rules // if (apply_explicit_conv_rules) { - var candidate_set = new List (); + 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 +904,16 @@ namespace Mono.CSharp { /// /// Finds the most specific target Tx according to section 13.4.4 /// - static public Type FindMostSpecificTarget (IList list, - Type target, bool apply_explicit_conv_rules) + static public TypeSpec FindMostSpecificTarget (IList list, + TypeSpec target, bool apply_explicit_conv_rules) { - var tgt_types_set = new List (); + var tgt_types_set = new List (); // // If any operator converts to T then Tx = T // foreach (var mi in list){ - Type ret_type = TypeManager.TypeToCoreType (mi.ReturnType); + TypeSpec ret_type = mi.ReturnType; if (ret_type == target) return ret_type; @@ -944,11 +924,11 @@ namespace Mono.CSharp { // Explicit conv rules // if (apply_explicit_conv_rules) { - var candidate_set = new List (); + 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,241 +953,210 @@ namespace Mono.CSharp { /// /// User-defined Implicit conversions /// - static public Expression ImplicitUserConversion (ResolveContext ec, Expression source, - Type target, Location loc) + static public Expression ImplicitUserConversion (ResolveContext ec, Expression source, TypeSpec target, Location loc) { - return UserDefinedConversion (ec, source, target, loc, false, true); + return UserDefinedConversion (ec, source, target, true, loc); } /// /// User-defined Explicit conversions /// - static Expression ExplicitUserConversion (ResolveContext ec, Expression source, - Type target, Location loc) + static Expression ExplicitUserConversion (ResolveContext ec, Expression source, TypeSpec target, Location loc) { - return UserDefinedConversion (ec, source, target, loc, true, true); + return UserDefinedConversion (ec, source, target, false, loc); } - static void AddConversionOperators (List 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 (var m in mg.Methods) { - AParametersCollection pd = m.Parameters; - Type return_type = TypeManager.TypeToCoreType (m.ReturnType); - Type arg_type = pd.Types [0]; - - 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. - if (target_type != return_type) { - expr.SetType (return_type); - if (!ImplicitStandardConversionExists (expr, target_type)) { - if (!look_for_explicit) - continue; - expr.SetType (target_type); - if (!ImplicitStandardConversionExists (expr, return_type)) - continue; - } - } + Expression texpr = null; - // See LAMESPEC: Exclude IntPtr -> int conversion - if (source_type == TypeManager.uintptr_type && return_type == TypeManager.uint32_type) + foreach (MethodSpec op in operators) { + + // Can be null because MemberCache.GetUserOperator does not resize the array + if (op == null) continue; - list.Add (m); - } - - 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 MethodSpec GetConversionOperator (CompilerContext ctx, Type container_type, Expression source, Type target_type, bool look_for_explicit) - { - var ops = new List (4); - - Type source_type = source.Type; + var t = op.Parameters.Types[0]; + if (source.Type != t && !ImplicitStandardConversionExists (source, t)) { + if (implicitOnly) + continue; - if (source_type != TypeManager.decimal_type) { - AddConversionOperators (ops, source, target_type, look_for_explicit, - Expression.MethodLookup (ctx, container_type, source_type, "op_Implicit", Location.Null) as MethodGroupExpr); - if (look_for_explicit) { - AddConversionOperators (ops, source, target_type, look_for_explicit, - Expression.MethodLookup (ctx, - container_type, source_type, "op_Explicit", Location.Null) as MethodGroupExpr); + if (!ImplicitStandardConversionExists (new EmptyExpression (t), source.Type)) + continue; } - } - if (target_type != TypeManager.decimal_type) { - AddConversionOperators (ops, source, target_type, look_for_explicit, - Expression.MethodLookup (ctx, container_type, target_type, "op_Implicit", Location.Null) as MethodGroupExpr); - if (look_for_explicit) { - AddConversionOperators (ops, source, target_type, look_for_explicit, - Expression.MethodLookup (ctx, - container_type, target_type, "op_Explicit", Location.Null) as MethodGroupExpr); - } - } + t = op.ReturnType; - if (ops.Count == 0) - return null; + // LAMESPEC: Exclude UIntPtr -> int conversion + if (t == TypeManager.uint32_type && source.Type == TypeManager.uintptr_type) + continue; - Type most_specific_source = FindMostSpecificSource (ops, source, look_for_explicit); - if (most_specific_source == null) - return null; + if (target != t && !ImplicitStandardConversionExists (new EmptyExpression (t), target)) { + if (implicitOnly) + continue; - Type most_specific_target = FindMostSpecificTarget (ops, target_type, look_for_explicit); - if (most_specific_target == null) - return null; + if (texpr == null) + texpr = new EmptyExpression (target); - MethodSpec method = null; + if (!ImplicitStandardConversionExists (texpr, t)) + continue; + } - foreach (var m in ops) { - if (TypeManager.TypeToCoreType (m.ReturnType) != most_specific_target) - continue; - if (m.Parameters.Types [0] != most_specific_source) - continue; - // Ambiguous: more than one conversion operator satisfies the signature. - if (method != null) - return null; - method = m; - } + if (candidates == null) + candidates = new List (); - return method; + candidates.Add (op); + } } - /// - /// User-defined conversions - /// - public static Expression UserDefinedConversion (ResolveContext ec, Expression source, - Type target, Location loc, - bool look_for_explicit, bool return_convert) + // + // User-defined conversions + // + static Expression UserDefinedConversion (ResolveContext ec, Expression source, TypeSpec target, bool implicitOnly, Location loc) { - Type source_type = source.Type; - MethodSpec method = null; - Expression expr = null; - - object o; - DoubleHash hash; - if (look_for_explicit) { - hash = explicit_conv; - } else { - // Implicit user operators cannot convert to interfaces - if (target.IsInterface) - return null; + List candidates = null; - hash = implicit_conv; - } + // + // If S or T are nullable types, S0 and T0 are their underlying types + // otherwise S0 and T0 are equal to S and T respectively. + // + TypeSpec source_type = source.Type; + TypeSpec target_type = target; + Expression unwrap; - if (!(source is Constant) && hash.Lookup (source_type, target, out o)) { - method = (MethodSpec) o; - } else { - if (TypeManager.IsDynamicType (source_type)) + 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; - method = GetConversionOperator (ec.Compiler, null, source, target, look_for_explicit); + unwrap = source = Nullable.Unwrap.Create (source); + source_type = source.Type; + } else { + unwrap = null; } - if (method != null) { - Type most_specific_source = method.Parameters.Types[0]; + if (TypeManager.IsNullableType (target_type)) + target_type = Nullable.NullableInfo.GetUnderlyingType (target_type); - // - // This will do the conversion to the best match that we - // found. Now we need to perform an implict standard conversion - // if the best match was not the type that we were requested - // by target. - // - if (look_for_explicit) { - ReportPrinter temp = new SessionReportPrinter (); - ReportPrinter prev = ec.Report.SetPrinter (temp); + // Only these containers can contain a user defined implicit or explicit operators + const MemberKind user_conversion_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.TypeParameter; - expr = ExplicitConversionStandard (ec, source, most_specific_source, loc); + if ((source_type.Kind & user_conversion_kinds) != 0 && source_type != TypeManager.decimal_type) { + bool declared_only = source_type.IsStruct; - ec.Report.SetPrinter (prev); - if (temp.ErrorsCount != 0) - expr = null; - } else { - if (ImplicitStandardConversionExists (source, most_specific_source)) - expr = ImplicitConversionStandard (ec, source, most_specific_source, loc); - else - expr = null; + var operators = MemberCache.GetUserOperator (source_type, Operator.OpType.Implicit, declared_only); + if (operators != null) { + FindApplicableUserDefinedConversionOperators (operators, source, target_type, implicitOnly, ref candidates); } - } - - if (expr == null) { - bool nullable = false; - if (TypeManager.IsNullableType (source_type)) { - source = Nullable.Unwrap.Create (source); - nullable = true; + if (!implicitOnly) { + operators = MemberCache.GetUserOperator (source_type, Operator.OpType.Explicit, declared_only); + if (operators != null) { + FindApplicableUserDefinedConversionOperators (operators, source, target_type, false, ref candidates); + } } + } - Type target_underlying; - if (TypeManager.IsNullableType (target)) { - target_underlying = TypeManager.GetTypeArguments (target)[0]; - nullable = true; - } else { - // No implicit conversion S? -> T for non-reference type T - if (!look_for_explicit && !TypeManager.IsReferenceType (target)) - nullable = false; + if ((target.Kind & user_conversion_kinds) != 0 && target != TypeManager.decimal_type) { + bool declared_only = target.IsStruct || implicitOnly; - target_underlying = target; + var operators = MemberCache.GetUserOperator (target_type, Operator.OpType.Implicit, declared_only); + if (operators != null) { + FindApplicableUserDefinedConversionOperators (operators, source, target_type, implicitOnly, ref candidates); } - if (nullable) { - expr = UserDefinedConversion (ec, source, target_underlying, loc, look_for_explicit, return_convert); + if (!implicitOnly) { + operators = MemberCache.GetUserOperator (target_type, Operator.OpType.Explicit, declared_only); + if (operators != null) { + FindApplicableUserDefinedConversionOperators (operators, source, target_type, false, ref candidates); + } + } + } - // Do result expression lifting only when it's needed - if (expr != null && (!look_for_explicit || TypeManager.IsReferenceType (target))) - expr = new Nullable.Lifted (expr, source, target).Resolve (ec); + if (candidates == null) + return null; - return expr; - } + // + // 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 { - expr = new UserCast (method, expr, loc).Resolve (ec); + s_x = FindMostSpecificSource (candidates, source, !implicitOnly); + if (s_x == null) + return null; + + t_x = FindMostSpecificTarget (candidates, target, !implicitOnly); + if (t_x == null) + return null; + + most_specific_operator = candidates[0]; - if (return_convert && !TypeManager.IsEqual (expr.Type, target)) { - if (look_for_explicit) { - expr = ExplicitConversionStandard (ec, expr, target, loc); - } else { - expr = ImplicitConversionStandard (ec, expr, target, loc); + for (int i = 1; i < candidates.Count; ++i) { + if (candidates[i].ReturnType == t_x && candidates[i].Parameters.Types[0] == s_x) { + most_specific_operator = candidates[i]; + break; } } } - if (!(source is Constant)) - hash.Insert (source_type, target, method); + // + // Convert input type when it's different to best operator argument + // + if (s_x != source.Type) + source = implicitOnly ? + ImplicitConversionStandard (ec, source, s_x, loc) : + ExplicitConversionStandard (ec, source, s_x, loc); + + source = new UserCast (most_specific_operator, source, loc).Resolve (ec); + + // + // Convert result type when it's different to best operator return type + // + 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; + + source = implicitOnly ? + ImplicitConversionStandard (ec, source, target_type, loc) : + ExplicitConversionStandard (ec, source, target_type, loc); + } + + // + // Source expression is of nullable type, lift the result in case of it's null + // + if (unwrap != null && (TypeManager.IsReferenceType (target) || target_type != target)) + source = new Nullable.Lifted (source, unwrap, target).Resolve (ec); + else if (target_type != target) + source = Nullable.Wrap.Create (source, target); - return expr; + return source; } /// @@ -1216,7 +1165,7 @@ namespace Mono.CSharp { /// in a context that expects a `target_type'. /// static public Expression ImplicitConversion (ResolveContext ec, Expression expr, - Type target_type, Location loc) + TypeSpec target_type, Location loc) { Expression e; @@ -1246,12 +1195,12 @@ namespace Mono.CSharp { /// user defined implicit conversions are excluded. /// static public Expression ImplicitConversionStandard (ResolveContext ec, Expression expr, - Type target_type, Location loc) + TypeSpec target_type, Location loc) { return ImplicitConversionStandard (ec, expr, target_type, loc, false); } - static Expression ImplicitConversionStandard (ResolveContext 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)){ @@ -1269,7 +1218,7 @@ namespace Mono.CSharp { } } - Type expr_type = expr.Type; + TypeSpec expr_type = expr.Type; Expression e; if (expr_type.Equals (target_type)) { @@ -1278,7 +1227,7 @@ namespace Mono.CSharp { return null; } - if (TypeManager.IsVariantOf (expr_type, target_type)) { + if (TypeSpecComparer.Variant.IsEqual (expr_type, target_type)) { return expr; } @@ -1308,17 +1257,19 @@ 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).Resolve (ec); + 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.IsUnsafe) { @@ -1361,13 +1312,13 @@ namespace Mono.CSharp { /// an error is signaled /// static public Expression ImplicitConversionRequired (ResolveContext ec, Expression source, - Type target_type, Location loc) + TypeSpec target_type, Location loc) { Expression e = ImplicitConversion (ec, source, target_type, loc); if (e != null) return e; - if (TypeManager.IsDynamicType (source.Type)) { + if (source.Type == InternalType.Dynamic) { Arguments args = new Arguments (1); args.Add (new Argument (source)); return new DynamicConversion (target_type, 0, args, loc).Resolve (ec); @@ -1398,10 +1349,10 @@ namespace Mono.CSharp { /// Int16->UIntPtr /// /// - public static Expression ExplicitNumericConversion (Expression expr, Type target_type) + public static Expression ExplicitNumericConversion (Expression expr, TypeSpec target_type) { - Type expr_type = expr.Type; - Type real_target_type = target_type; + TypeSpec expr_type = expr.Type; + TypeSpec real_target_type = target_type; if (expr_type == TypeManager.sbyte_type){ // @@ -1651,7 +1602,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) @@ -1666,10 +1617,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 // @@ -1679,43 +1628,39 @@ 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 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) + 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 && TypeManager.IsSubclassOf (target_type, source_type)) return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); - } // // From any interface-type S to to any class type T, provided T is not // sealed, or provided T implements S. // if (source_type.IsInterface) { - if (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)) { + if (!target_type.IsSealed || target_type.ImplementsInterface (source_type)) { if (target_type.IsClass) return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); @@ -1727,17 +1672,20 @@ namespace Mono.CSharp { } // - // 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 // @@ -1752,17 +1700,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; @@ -1773,12 +1721,20 @@ 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)) { + return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); + } + // // From System delegate to any delegate-type // @@ -1793,9 +1749,9 @@ namespace Mono.CSharp { /// type is expr.Type to `target_type'. /// static public Expression ExplicitConversionCore (ResolveContext ec, Expression expr, - Type target_type, Location loc) + 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); @@ -1803,41 +1759,60 @@ 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 @@ -1858,9 +1833,9 @@ namespace Mono.CSharp { return null; } - public static Expression ExplicitUnsafe (Expression expr, Type target_type) + public static Expression ExplicitUnsafe (Expression expr, TypeSpec target_type) { - Type expr_type = expr.Type; + TypeSpec expr_type = expr.Type; if (target_type.IsPointer){ if (expr_type.IsPointer) @@ -1908,7 +1883,7 @@ namespace Mono.CSharp { /// Same as ExplicitConversion, only it doesn't include user defined conversions /// static public Expression ExplicitConversionStandard (ResolveContext ec, Expression expr, - Type target_type, Location l) + TypeSpec target_type, Location l) { int errors = ec.Report.Errors; Expression ne = ImplicitConversionStandard (ec, expr, target_type, l); @@ -1938,7 +1913,7 @@ namespace Mono.CSharp { /// type is expr.Type to `target_type'. /// static public Expression ExplicitConversion (ResolveContext ec, Expression expr, - Type target_type, Location loc) + TypeSpec target_type, Location loc) { Expression e = ExplicitConversionCore (ec, expr, target_type, loc); if (e != null) { @@ -1956,10 +1931,10 @@ namespace Mono.CSharp { return e; } - Type expr_type = expr.Type; + TypeSpec expr_type = expr.Type; if (TypeManager.IsNullableType (target_type)) { if (TypeManager.IsNullableType (expr_type)) { - Type target = TypeManager.TypeToCoreType (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) @@ -1969,19 +1944,18 @@ namespace Mono.CSharp { } else if (expr_type == TypeManager.object_type) { return new UnboxCast (expr, target_type); } else { - Type target = TypeManager.TypeToCoreType (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, false); + 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 = Nullable.Unwrap.Create (expr, false); e = ExplicitConversionCore (ec, e, target_type, loc); if (e != null) return EmptyCast.Create (e, target_type);