X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fconvert.cs;h=36c5626bcc32dd190a10ff102953fb65f56ea8e3;hb=efd53c8e2f1823568309a2920091b724be0feff8;hp=3fcffa8d7b8912e3ee4e029e3514e75bf8c41d13;hpb=adc40c3f99d86f885d86f081cc75d33332164051;p=mono.git diff --git a/mcs/mcs/convert.cs b/mcs/mcs/convert.cs index 3fcffa8d7b8..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 @@ -126,34 +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) { + // + // 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); } - -/* - 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); - } - } -*/ - 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; @@ -331,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; } // @@ -670,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) { @@ -681,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); } // @@ -906,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; @@ -932,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); + } } // @@ -1005,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); } /// @@ -1013,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 @@ -1038,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) @@ -1056,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) @@ -1077,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; @@ -1089,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 @@ -1114,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); } } } @@ -1130,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); } } } @@ -1158,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; @@ -1178,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 ()); @@ -1203,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 @@ -1236,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; @@ -1261,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 @@ -1442,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; } @@ -1812,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; @@ -1849,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) @@ -1893,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; @@ -1971,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; } @@ -2205,6 +2267,7 @@ namespace Mono.CSharp { } e = ExplicitUserConversion (ec, expr, target_type, loc); + if (e != null) return e;