[mcs] C# 7 tuple (foundation only).
[mono.git] / mcs / mcs / convert.cs
index 3adb909e6f5afc782964f929c325165b6694813d..a99e3fde628b60061aae8448ab3621c23a7fad9c 100644 (file)
@@ -679,6 +679,80 @@ 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<Expression> (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) {
+                               var elementType = srcTypeArgument [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
                //
@@ -758,7 +832,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
                        //
@@ -1420,6 +1497,14 @@ 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;
+                       }
+
                        e = ImplicitNumericConversion (expr, expr_type, target_type);
                        if (e != null)
                                return e;
@@ -1499,14 +1584,15 @@ namespace Mono.CSharp {
                ///   ImplicitConversion.  If there is no implicit conversion, then
                ///   an error is signaled
                /// </summary>
-               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;
                }