X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fconvert.cs;h=36c5626bcc32dd190a10ff102953fb65f56ea8e3;hb=95e805c52a5be95fd4ca1cae9f35238d5a2416c4;hp=6fc03b11d9e033c387ef9ec73c5b60561c4d1d3a;hpb=6352c16dd5306ccb8bedc742bf99505688695dc6;p=mono.git diff --git a/mcs/mcs/convert.cs b/mcs/mcs/convert.cs index 6fc03b11d9e..36c5626bcc3 100644 --- a/mcs/mcs/convert.cs +++ b/mcs/mcs/convert.cs @@ -27,6 +27,15 @@ namespace Mono.CSharp { // static class Convert { + [Flags] + public enum UserConversionRestriction + { + None = 0, + ImplicitOnly = 1, + ProbingOnly = 1 << 1, + NullableSourceOnly = 1 << 2 + + } // // From a one-dimensional array-type S[] to System.Collections.IList and base // interfaces of this interface, provided there is an implicit reference conversion @@ -71,19 +80,14 @@ namespace Mono.CSharp { // From T to a type parameter U, provided T depends on U // if (target_type.IsGenericParameter) { - if (expr_type.TypeArguments != null) { - foreach (var targ in expr_type.TypeArguments) { - if (!TypeSpecComparer.Override.IsEqual (target_type, targ)) - continue; - - if (expr == null) - return EmptyExpression.Null; + if (expr_type.TypeArguments != null && expr_type.HasDependencyOn (target_type)) { + if (expr == null) + return EmptyExpression.Null; - if (expr_type.IsReferenceType && !((TypeParameterSpec)target_type).IsReferenceType) - return new BoxedCast (expr, target_type); + if (expr_type.IsReferenceType && !((TypeParameterSpec) target_type).IsReferenceType) + return new BoxedCast (expr, target_type); - return new ClassCast (expr, target_type); - } + return new ClassCast (expr, target_type); } return null; @@ -131,38 +135,39 @@ namespace Mono.CSharp { return null; } - static Expression ExplicitTypeParameterConversion (Expression source, TypeSpec source_type, TypeSpec target_type) + static Expression ExplicitTypeParameterConversionFromT (Expression source, TypeSpec source_type, TypeSpec target_type) { 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; - - return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); - } - } -/* - if (target_tp.Interfaces != null) { - foreach (TypeSpec iface in target_tp.Interfaces) { - if (!TypeManager.IsGenericParameter (iface)) - continue; - - if (TypeManager.IsSubclassOf (source_type, iface)) - return source == null ? EmptyExpression.Null : new ClassCast (source, target_type, true); - } + // + // From a type parameter U to T, provided T depends on U + // + if (target_tp.TypeArguments != null && target_tp.HasDependencyOn (source_type)) { + return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); } -*/ - return null; } + // + // From T to any interface-type I provided there is not already an implicit conversion from T to I + // if (target_type.IsInterface) return source == null ? EmptyExpression.Null : new ClassCast (source, target_type, true); return null; } + static Expression ExplicitTypeParameterConversionToT (Expression source, TypeSpec source_type, TypeParameterSpec target_type) + { + // + // From the effective base class C of T to T and from any base class of C to T + // + var effective = target_type.GetEffectiveBase (); + if (TypeSpecComparer.IsEqual (effective, source_type) || TypeSpec.IsBaseClass (effective, source_type, false)) + return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); + + return null; + } + public static Expression ImplicitReferenceConversion (Expression expr, TypeSpec target_type, bool explicit_cast) { TypeSpec expr_type = expr.Type; @@ -340,7 +345,7 @@ namespace Mono.CSharp { if (target_type.Kind == MemberKind.InternalCompilerType) return target_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic; - return TypeSpec.IsReferenceType (target_type); + return TypeSpec.IsReferenceType (target_type) || target_type.Kind == MemberKind.PointerType; } // @@ -679,7 +684,7 @@ namespace Mono.CSharp { // public static bool ImplicitConversionExists (ResolveContext ec, Expression expr, TypeSpec target_type) { - if (ImplicitStandardConversionExists (expr, target_type)) + if (ImplicitStandardConversionExists (ec, expr, target_type)) return true; if (expr.Type == InternalType.AnonymousMethod) { @@ -690,21 +695,33 @@ namespace Mono.CSharp { return ame.ImplicitStandardConversionExists (ec, target_type); } + // Conversion from __arglist to System.ArgIterator + if (expr.Type == InternalType.Arglist) + return target_type == ec.Module.PredefinedTypes.ArgIterator.TypeSpec; + + return UserDefinedConversion (ec, expr, target_type, + UserConversionRestriction.ImplicitOnly | UserConversionRestriction.ProbingOnly, Location.Null) != null; + } + + public static bool ImplicitStandardConversionExists (ResolveContext rc, Expression expr, TypeSpec target_type) + { if (expr.eclass == ExprClass.MethodGroup) { - if (target_type.IsDelegate && ec.Module.Compiler.Settings.Version != LanguageVersion.ISO_1) { + if (target_type.IsDelegate && rc.Module.Compiler.Settings.Version != LanguageVersion.ISO_1) { MethodGroupExpr mg = expr as MethodGroupExpr; if (mg != null) - return DelegateCreation.ImplicitStandardConversionExists (ec, mg, target_type); + return DelegateCreation.ImplicitStandardConversionExists (rc, mg, target_type); } return false; } - // Conversion from __arglist to System.ArgIterator - if (expr.Type == InternalType.Arglist) - return target_type == ec.Module.PredefinedTypes.ArgIterator.TypeSpec; + var interpolated_string = expr as InterpolatedString; + if (interpolated_string != null) { + if (target_type == rc.Module.PredefinedTypes.IFormattable.TypeSpec || target_type == rc.Module.PredefinedTypes.FormattableString.TypeSpec) + return true; + } - return UserDefinedConversion (ec, expr, target_type, true, true, Location.Null) != null; + return ImplicitStandardConversionExists (expr, target_type); } // @@ -915,7 +932,7 @@ namespace Mono.CSharp { // by making use of FindMostEncomp* methods. Applies the correct rules separately // for explicit and implicit conversion operators. // - static TypeSpec FindMostSpecificSource (List list, TypeSpec sourceType, Expression source, bool apply_explicit_conv_rules) + static TypeSpec FindMostSpecificSource (ResolveContext rc, List list, TypeSpec sourceType, Expression source, bool apply_explicit_conv_rules) { TypeSpec[] src_types_set = null; @@ -941,12 +958,16 @@ namespace Mono.CSharp { var candidate_set = new List (); foreach (TypeSpec param_type in src_types_set){ - if (ImplicitStandardConversionExists (source, param_type)) + if (ImplicitStandardConversionExists (rc, source, param_type)) candidate_set.Add (param_type); } - if (candidate_set.Count != 0) + if (candidate_set.Count != 0) { + if (source.eclass == ExprClass.MethodGroup) + return InternalType.FakeInternalType; + return FindMostEncompassedType (candidate_set); + } } // @@ -1014,7 +1035,7 @@ namespace Mono.CSharp { /// static public Expression ImplicitUserConversion (ResolveContext ec, Expression source, TypeSpec target, Location loc) { - return UserDefinedConversion (ec, source, target, true, false, loc); + return UserDefinedConversion (ec, source, target, UserConversionRestriction.ImplicitOnly, loc); } /// @@ -1022,10 +1043,10 @@ namespace Mono.CSharp { /// static Expression ExplicitUserConversion (ResolveContext ec, Expression source, TypeSpec target, Location loc) { - return UserDefinedConversion (ec, source, target, false, false, loc); + return UserDefinedConversion (ec, source, target, 0, loc); } - static void FindApplicableUserDefinedConversionOperators (IList operators, Expression source, TypeSpec target, bool implicitOnly, ref List candidates) + static void FindApplicableUserDefinedConversionOperators (ResolveContext rc, IList operators, Expression source, TypeSpec target, UserConversionRestriction restr, ref List candidates) { if (source.Type.IsInterface) { // Neither A nor B are interface-types @@ -1047,14 +1068,17 @@ namespace Mono.CSharp { continue; var t = op.Parameters.Types[0]; - if (source.Type != t && !ImplicitStandardConversionExists (source, t)) { - if (implicitOnly) + if (source.Type != t && !ImplicitStandardConversionExists (rc, source, t)) { + if ((restr & UserConversionRestriction.ImplicitOnly) != 0) continue; if (!ImplicitStandardConversionExists (new EmptyExpression (t), source.Type)) - continue; + continue; } + if ((restr & UserConversionRestriction.NullableSourceOnly) != 0 && !t.IsNullableType) + continue; + t = op.ReturnType; if (t.IsInterface) @@ -1065,7 +1089,7 @@ namespace Mono.CSharp { t = Nullable.NullableInfo.GetUnderlyingType (t); if (!ImplicitStandardConversionExists (new EmptyExpression (t), target)) { - if (implicitOnly) + if ((restr & UserConversionRestriction.ImplicitOnly) != 0) continue; if (texpr == null) @@ -1086,7 +1110,7 @@ namespace Mono.CSharp { // // User-defined conversions // - static Expression UserDefinedConversion (ResolveContext ec, Expression source, TypeSpec target, bool implicitOnly, bool probingOnly, Location loc) + public static Expression UserDefinedConversion (ResolveContext rc, Expression source, TypeSpec target, UserConversionRestriction restr, Location loc) { List candidates = null; @@ -1098,6 +1122,7 @@ namespace Mono.CSharp { TypeSpec target_type = target; Expression source_type_expr; bool nullable_source = false; + var implicitOnly = (restr & UserConversionRestriction.ImplicitOnly) != 0; if (source_type.IsNullableType) { // No unwrapping conversion S? -> T for non-reference types @@ -1123,13 +1148,13 @@ namespace Mono.CSharp { var operators = MemberCache.GetUserOperator (source_type, Operator.OpType.Implicit, declared_only); if (operators != null) { - FindApplicableUserDefinedConversionOperators (operators, source_type_expr, target_type, implicitOnly, ref candidates); + FindApplicableUserDefinedConversionOperators (rc, operators, source_type_expr, target_type, restr, ref candidates); } if (!implicitOnly) { operators = MemberCache.GetUserOperator (source_type, Operator.OpType.Explicit, declared_only); if (operators != null) { - FindApplicableUserDefinedConversionOperators (operators, source_type_expr, target_type, false, ref candidates); + FindApplicableUserDefinedConversionOperators (rc, operators, source_type_expr, target_type, restr, ref candidates); } } } @@ -1139,13 +1164,13 @@ namespace Mono.CSharp { var operators = MemberCache.GetUserOperator (target_type, Operator.OpType.Implicit, declared_only); if (operators != null) { - FindApplicableUserDefinedConversionOperators (operators, source_type_expr, target_type, implicitOnly, ref candidates); + FindApplicableUserDefinedConversionOperators (rc, operators, source_type_expr, target_type, restr, ref candidates); } if (!implicitOnly) { operators = MemberCache.GetUserOperator (target_type, Operator.OpType.Explicit, declared_only); if (operators != null) { - FindApplicableUserDefinedConversionOperators (operators, source_type_expr, target_type, false, ref candidates); + FindApplicableUserDefinedConversionOperators (rc, operators, source_type_expr, target_type, restr, ref candidates); } } } @@ -1167,7 +1192,7 @@ namespace Mono.CSharp { // Pass original source type to find the best match against input type and // not the unwrapped expression // - s_x = FindMostSpecificSource (candidates, source.Type, source_type_expr, !implicitOnly); + s_x = FindMostSpecificSource (rc, candidates, source.Type, source_type_expr, !implicitOnly); if (s_x == null) return null; @@ -1187,16 +1212,18 @@ namespace Mono.CSharp { // // Unless running in probing more // - if (!probingOnly) { - MethodSpec ambig_arg = null; + if ((restr & UserConversionRestriction.ProbingOnly) == 0) { + MethodSpec ambig_arg = candidates [0]; + most_specific_operator = candidates [1]; + /* foreach (var candidate in candidates) { if (candidate.ReturnType == t_x) most_specific_operator = candidate; else if (candidate.Parameters.Types[0] == s_x) ambig_arg = candidate; } - - ec.Report.Error (457, loc, + */ + rc.Report.Error (457, loc, "Ambiguous user defined operators `{0}' and `{1}' when converting from `{2}' to `{3}'", ambig_arg.GetSignatureForError (), most_specific_operator.GetSignatureForError (), source.Type.GetSignatureForError (), target.GetSignatureForError ()); @@ -1212,21 +1239,21 @@ namespace Mono.CSharp { if (s_x != source_type) { var c = source as Constant; if (c != null) { - source = c.Reduce (ec, s_x); + source = c.Reduce (rc, s_x); if (source == null) c = null; } if (c == null) { source = implicitOnly ? - ImplicitConversionStandard (ec, source_type_expr, s_x, loc) : - ExplicitConversionStandard (ec, source_type_expr, s_x, loc); + ImplicitConversionStandard (rc, source_type_expr, s_x, loc) : + ExplicitConversionStandard (rc, source_type_expr, s_x, loc); } } else { source = source_type_expr; } - source = new UserCast (most_specific_operator, source, loc).Resolve (ec); + source = new UserCast (most_specific_operator, source, loc).Resolve (rc); // // Convert result type when it's different to best operator return type @@ -1245,19 +1272,19 @@ namespace Mono.CSharp { var unwrap = Nullable.Unwrap.CreateUnwrapped (source); source = implicitOnly ? - ImplicitConversionStandard (ec, unwrap, target_type, loc) : - ExplicitConversionStandard (ec, unwrap, target_type, loc); + ImplicitConversionStandard (rc, unwrap, target_type, loc) : + ExplicitConversionStandard (rc, unwrap, target_type, loc); if (source == null) return null; if (target.IsNullableType) - source = new Nullable.LiftedConversion (source, unwrap, target).Resolve (ec); + source = new Nullable.LiftedConversion (source, unwrap, target).Resolve (rc); } } else { source = implicitOnly ? - ImplicitConversionStandard (ec, source, target_type, loc) : - ExplicitConversionStandard (ec, source, target_type, loc); + ImplicitConversionStandard (rc, source, target_type, loc) : + ExplicitConversionStandard (rc, source, target_type, loc); if (source == null) return null; @@ -1270,7 +1297,7 @@ namespace Mono.CSharp { // only non-nullable type we need to lift it manually // if (nullable_source && !s_x.IsNullableType) - return new Nullable.LiftedConversion (source, source_type_expr, target).Resolve (ec); + return new Nullable.LiftedConversion (source, source_type_expr, target).Resolve (rc); // // Target is of nullable type but source type is not, wrap the result expression @@ -1451,6 +1478,12 @@ namespace Mono.CSharp { if (expr_type.IsStruct && TypeSpecComparer.IsEqual (expr_type, target_type)) return expr_type == target_type ? expr : EmptyCast.Create (expr, target_type); + var interpolated_string = expr as InterpolatedString; + if (interpolated_string != null) { + if (target_type == ec.Module.PredefinedTypes.IFormattable.TypeSpec || target_type == ec.Module.PredefinedTypes.FormattableString.TypeSpec) + return interpolated_string.ConvertTo (ec, target_type); + } + return null; } @@ -1467,6 +1500,7 @@ namespace Mono.CSharp { return e; source.Error_ValueCannotBeConverted (ec, target_type, false); + return null; } @@ -1820,10 +1854,10 @@ namespace Mono.CSharp { return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type); // - // Explicit type parameter conversion. + // Explicit type parameter conversion from T // if (source_type.Kind == MemberKind.TypeParameter) - return ExplicitTypeParameterConversion (source, source_type, target_type); + return ExplicitTypeParameterConversionFromT (source, source_type, target_type); bool target_is_value_type = target_type.Kind == MemberKind.Struct || target_type.Kind == MemberKind.Enum; @@ -1857,6 +1891,9 @@ namespace Mono.CSharp { // From any interface-type S to to any class type T, provided T is not // sealed, or provided T implements S. // + // This also covers Explicit conversions involving type parameters + // section From any interface type to T + // if (source_type.Kind == MemberKind.Interface) { if (!target_type.IsSealed || target_type.ImplementsInterface (source_type, true)) { if (source == null) @@ -1901,10 +1938,23 @@ namespace Mono.CSharp { if (source_array.Rank == target_array.Rank) { source_type = source_array.Element; - if (!TypeSpec.IsReferenceType (source_type)) - return null; - var target_element = target_array.Element; + + // + // LAMESPEC: Type parameters are special cased somehow but + // only when both source and target elements are type parameters + // + if ((source_type.Kind & target_element.Kind & MemberKind.TypeParameter) == MemberKind.TypeParameter) { + // + // Conversion is allowed unless source element type has struct constrain + // + if (TypeSpec.IsValueType (source_type)) + return null; + } else { + if (!TypeSpec.IsReferenceType (source_type)) + return null; + } + if (!TypeSpec.IsReferenceType (target_element)) return null; @@ -1979,6 +2029,10 @@ namespace Mono.CSharp { return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); } + var tps = target_type as TypeParameterSpec; + if (tps != null) + return ExplicitTypeParameterConversionToT (source, source_type, tps); + return null; } @@ -2213,6 +2267,7 @@ namespace Mono.CSharp { } e = ExplicitUserConversion (ec, expr, target_type, loc); + if (e != null) return e;