X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fconvert.cs;h=b11477c104394b7bc77075d6e4fa02827797529e;hb=30cddad5fb4c3d290906a6e6c33ecd8b07d8b48c;hp=05709f6ae471068a6d25302c3bfc4ec284ef93d5;hpb=35a8179e1ddcfbed00d4c4694f013803b44b5afb;p=mono.git diff --git a/mcs/mcs/convert.cs b/mcs/mcs/convert.cs index 05709f6ae47..b11477c1043 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 @@ -336,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,12 +679,84 @@ namespace Mono.CSharp { return null; } + static Expression ImplicitTupleLiteralConversion (ResolveContext rc, Expression source, TypeSpec targetType, Location loc) + { + var targetTypeArgument = targetType.TypeArguments; + if (source.Type.Arity != targetTypeArgument.Length) + return null; + + var namedTarget = targetType as NamedTupleSpec; + var tupleLiteral = source as TupleLiteral; + Expression instance; + + if (tupleLiteral == null && !ExpressionAnalyzer.IsInexpensiveLoad (source)) { + var expr_variable = LocalVariable.CreateCompilerGenerated (source.Type, rc.CurrentBlock, loc); + source = new CompilerAssign (expr_variable.CreateReferenceExpression (rc, loc), source, loc); + instance = expr_variable.CreateReferenceExpression (rc, loc); + } else { + instance = null; + } + + var converted = new List (targetType.Arity); + for (int i = 0; i < targetType.Arity; ++i) { + Expression elementSrc; + if (tupleLiteral != null) { + elementSrc = tupleLiteral.Elements [i].Expr; + + if (namedTarget != null) { + var elementSrcName = tupleLiteral.Elements [i].Name; + if (elementSrcName != null && elementSrcName != namedTarget.Elements [i]) { + rc.Report.Warning (8123, 1, loc, + "The tuple element name `{0}' is ignored because a different name or no name is specified by the target type `{1}'", + elementSrcName, namedTarget.GetSignatureForErrorWithNames ()); + } + } + } else { + elementSrc = new MemberAccess (instance, NamedTupleSpec.GetElementPropertyName (i)).Resolve (rc); + } + + var res = ImplicitConversionStandard (rc, elementSrc, targetTypeArgument [i], loc); + if (res == null) + return null; + + converted.Add (res); + } + + return new TupleLiteralConversion (source, targetType, converted, loc); + } + + static bool ImplicitTupleLiteralConversionExists (Expression source, TypeSpec targetType) + { + if (source.Type.Arity != targetType.Arity) + return false; + + var srcTypeArgument = source.Type.TypeArguments; + var targetTypeArgument = targetType.TypeArguments; + + var tupleLiteralElements = (source as TupleLiteral)?.Elements; + + for (int i = 0; i < targetType.Arity; ++i) { + if (tupleLiteralElements != null) { + if (!ImplicitStandardConversionExists (tupleLiteralElements[i].Expr, targetTypeArgument [i])) { + return false; + } + } else { + if (!ImplicitStandardConversionExists (new EmptyExpression (srcTypeArgument [i]), targetTypeArgument [i])) { + return false; + } + } + } + + return true; + } + + // // Full version of implicit conversion // 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) { @@ -686,21 +767,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); } // @@ -723,6 +816,9 @@ namespace Mono.CSharp { if (expr_type == target_type) return true; + if (expr_type == InternalType.ThrowExpr) + return target_type.Kind != MemberKind.InternalCompilerType; + if (target_type.IsNullableType) return ImplicitNulableConversion (null, expr, target_type) != null; @@ -734,7 +830,10 @@ namespace Mono.CSharp { if (ImplicitBoxingConversion (null, expr_type, target_type) != null) return true; - + + if (expr_type.IsTupleType && target_type.IsTupleType) + return ImplicitTupleLiteralConversionExists (expr, target_type); + // // Implicit Constant Expression Conversions // @@ -911,7 +1010,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; @@ -937,12 +1036,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); + } } // @@ -1010,7 +1113,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); } /// @@ -1018,10 +1121,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 @@ -1043,14 +1146,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) @@ -1061,7 +1167,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) @@ -1082,7 +1188,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; @@ -1094,6 +1200,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 @@ -1119,13 +1226,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); } } } @@ -1135,13 +1242,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); } } } @@ -1163,7 +1270,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; @@ -1183,16 +1290,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 ()); @@ -1208,21 +1317,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 @@ -1241,19 +1350,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; @@ -1266,7 +1375,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 @@ -1339,7 +1448,7 @@ namespace Mono.CSharp { Expression e; if (expr_type == target_type) { - if (expr_type != InternalType.NullLiteral && expr_type != InternalType.AnonymousMethod) + if (expr_type != InternalType.NullLiteral && expr_type != InternalType.AnonymousMethod && expr_type != InternalType.ThrowExpr) return expr; return null; } @@ -1365,6 +1474,10 @@ namespace Mono.CSharp { return null; } + if (expr_type == InternalType.ThrowExpr) { + return target_type.Kind == MemberKind.InternalCompilerType ? null : EmptyCast.Create (expr, target_type); + } + if (target_type.IsNullableType) return ImplicitNulableConversion (ec, expr, target_type); @@ -1382,6 +1495,19 @@ namespace Mono.CSharp { return c; } + if (expr_type.IsTupleType) { + if (target_type.IsTupleType) + return ImplicitTupleLiteralConversion (ec, expr, target_type, loc); + + if (expr is TupleLiteral && TupleLiteral.ContainsNoTypeElement (expr_type)) + return null; + } + + if (expr is ReferenceExpression) { + // Only identify conversion is allowed + return null; + } + e = ImplicitNumericConversion (expr, expr_type, target_type); if (e != null) return e; @@ -1447,6 +1573,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; } @@ -1455,14 +1587,15 @@ namespace Mono.CSharp { /// ImplicitConversion. If there is no implicit conversion, then /// an error is signaled /// - static public Expression ImplicitConversionRequired (ResolveContext ec, Expression source, + public static Expression ImplicitConversionRequired (ResolveContext ec, Expression source, TypeSpec target_type, Location loc) { Expression e = ImplicitConversion (ec, source, target_type, loc); if (e != null) return e; - source.Error_ValueCannotBeConverted (ec, target_type, false); + if (target_type != InternalType.ErrorType) + source.Error_ValueCannotBeConverted (ec, target_type, false); return null; } @@ -1901,10 +2034,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; @@ -2217,6 +2363,7 @@ namespace Mono.CSharp { } e = ExplicitUserConversion (ec, expr, target_type, loc); + if (e != null) return e;